I am trying to take ADC reading from two current sensors and two thermistors. But the ADC buffer always returns zero. Is there something wrong with the code?
// PIC32MX795F512L Configuration Bit Settings
// 'C' source line config statements
// DEVCFG3
#pragma config USERID = 0xFFFF // Enter Hexadecimal value (Enter Hexadecimal value)
#pragma config FSRSSEL = PRIORITY_7 // SRS Select (SRS Priority 7)
#pragma config FMIIEN = ON // Ethernet RMII/MII Enable (MII Enabled)
#pragma config FETHIO = ON // Ethernet I/O Pin Select (Default Ethernet I/O)
#pragma config FCANIO = ON // CAN I/O Pin Select (Default CAN I/O)
#pragma config FUSBIDIO = ON // USB USID Selection (Controlled by the USB Module)
#pragma config FVBUSONIO = ON // USB VBUS ON Selection (Controlled by USB Module)
// DEVCFG2
#pragma config FPLLIDIV = DIV_2 // PLL Input Divider (2x Divider)
#pragma config FPLLMUL = MUL_20 // PLL Multiplier (20x Multiplier)
#pragma config UPLLIDIV = DIV_12 // USB PLL Input Divider (12x Divider)
#pragma config UPLLEN = OFF // USB PLL Enable (Disabled and Bypassed)
#pragma config FPLLODIV = DIV_4 // System PLL Output Clock Divider (PLL Divide by 4)
// DEVCFG1
#pragma config FNOSC = FRCPLL // Oscillator Selection Bits (Fast RC Osc with PLL)
#pragma config FSOSCEN = OFF // Secondary Oscillator Enable (Disabled)
#pragma config IESO = OFF // Internal/External Switch Over (Disabled)
#pragma config POSCMOD = OFF // Primary Oscillator Configuration (Primary osc disabled)
#pragma config OSCIOFNC = OFF // CLKO Output Signal Active on the OSCO Pin (Disabled)
#pragma config FPBDIV = DIV_1 // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/1)
#pragma config FCKSM = CSDCMD // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)
#pragma config WDTPS = PS1048576 // Watchdog Timer Postscaler (1:1048576)
#pragma config FWDTEN = OFF // Watchdog Timer Enable (WDT Disabled (SWDTEN Bit Controls))
// DEVCFG0
#pragma config DEBUG = OFF // Background Debugger Enable (Debugger is disabled)
#pragma config ICESEL = ICS_PGx1 // ICE/ICD Comm Channel Select (ICE EMUC1/EMUD1 pins shared with PGC1/PGD1)
#pragma config PWP = OFF // Program Flash Write Protect (Disable)
#pragma config BWP = OFF // Boot Flash Write Protect bit (Protection Disabled)
#pragma config CP = OFF // Code Protect (Protection Disabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<plib.h>
void initADC(void);
int ReadADC(int ch);
void delay_ms (WORD delay);
int main()
{
initADC();
unsigned int channel0;// conversion result as read from result buffer
unsigned int channel1;// conversion result as read from result buffer
unsigned int channel2;// conversion result as read from result buffer
unsigned int channel3;// conversion result as read from result buffer
while(1)
{
channel0=ReadADC(0);
delay_ms(0.5);
channel0=ReadADC(1);
delay_ms(0.5);
channel0=ReadADC(2);
delay_ms(0.5);
channel0=ReadADC(3);
delay_ms(0.5);
}
void initADC(void)
{
AD1PCFGbits.PCFG0 = 0; // Analog input in Analog mode
AD1PCFGbits.PCFG1 = 0;
AD1PCFGbits.PCFG2=0;
AD1PCFGbits.PCFG3=0;
AD1PCFGbits.PCFG4=0;
TRISBbits.TRISB6 = 1; // Pin set as input
TRISBbits.TRISB7 = 1;
TRISBbits.TRISB2=1;
TRISBbits.TRISB3=1;
TRISBbits.TRISB4=1;
AD1CHSbits.CH0NA = 0; // Channel 0 negative input is VR-
AD1CHSbits.CH0SA = 0; // Channel 0 positive input is AN0
AD1CON1bits.FORM = 0; // Integer 16-bit output
AD1CON1bits.SSRC = 0b111; // Internal counter ends sampling and starts conversion
AD1CSSL = 0; // No scanning required
AD1CON2bits.VCFG = 0; // Internal voltage references
AD1CON2bits.CSCNA = 0; // Do not scan inputs
AD1CON2bits.BUFM = 0; // Buffer configured as one 16-word buffer
AD1CON2bits.ALTS = 0; // Always use MUX A input multiplexer settings
AD1CON3bits.ADRC = 0; // Clock derived from PBclock
AD1CON3bits.ADCS = 0b00111111; // TAD
AD1CON3bits.SAMC = 0b11111; // 31 TAD auto-sample time
AD1CON1bits.ON = 1; // A/D converter module is operating
}
int ReadADC(int ch)
{
AD1CHSbits.CH0SA = ch; // Select input channel
AD1CON1bits.SAMP = 1; // Start sampling
while(!AD1CON1bits.DONE); // Wait for conversion to complete
return ADC1BUF0; // Read conversion result
}
If you are using portB as analog inputs, no need to use TRIS. Y
Make sure that you are give enough delay for scanning the inputs and reading the buffer.
Related
My goal is to control the position and speed of a Nema 17 stepper motor based on the euler angle of a BNO055 inertial measurement unit. I am using an ESP32 to flash the code via WIFI to rosserial. I am powering the Nema 17 with a 12V power source and the BNO055 with a small external 5V battery pack.
In summary, the stepper motor should move between 0-4100 steps which would be mapped to -90 and 90 degrees of the BNO055's y-axis.
For this, I need to read the output of the BNO055 sensor as often as possible and only change directions of the Nema 17 when the BNO055 has changed position relative to the mapping.
The PROBLEM I am having is that when I incorporate reading the sensor in my code, my motor starts to shake and does not rotate smoothly. I am wondering how I can get both things to work simultaneously (reading sensor and moving nema 17).
PS: I will control speed by calculating a PI control with the BNO055 sensor and adjusting the delayMicroseconds() accordingly... but first thing is to get the readings and motor movement smooth.
Below is a code snippet I am using to debug this problem:
#include <WiFi.h>
#include <ros.h>
#include <Wire.h>
#include <std_msgs/Header.h>
#include <std_msgs/String.h>
#include <geometry_msgs/Quaternion.h>
#include <HardwareSerial.h>
#include <analogWrite.h>
#include <MultiStepper.h>
#include <AccelStepper.h>
#include <Stepper.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include <math.h>
//////////////////////
// BNO055 //
//////////////////////
Adafruit_BNO055 bno_master = Adafruit_BNO055(55, 0x29);
Adafruit_BNO055 bno_slave = Adafruit_BNO055(55, 0x28);
geometry_msgs::Quaternion Quaternion;
std_msgs::String imu_msg;
#define I2C_SDA 21
#define I2C_SCL 22
TwoWire I2Cbno = TwoWire(0); // I2C connection will increase 6Hz data transmission
float ax_m, ay_m, az_m, ax_s, ay_s, az_s; // accelerometer
float gw_m, gx_m, gy_m, gz_m, gw_s, gx_s, gy_s, gz_s; // gyroscope
float ex_m, ey_m, ez_m, ex_s, ey_s, ez_s; // euler
float qw_m, qx_m, qy_m, qz_m, qw_s, qx_s, qy_s, qz_s; // quaternions
//////////////////////
// WiFi Definitions //
//////////////////////
const char* ssid = "FRITZ!Box 7430 PN"; // Sebas: "WLAN-481774"; Paula: "FRITZ!Box 7430 PN"; ICS: ICS24; Hotel Citadelle Blaye
const char* password = "37851923282869978396"; // Sebas: "Kerriganrocks!1337"; Paula: "37851923282869978396"; ICS: uZ)7xQ*0; citadelle
IPAddress server(192,168,178,112); // ip of your ROS server
IPAddress ip_address;
WiFiClient client;
int status = WL_IDLE_STATUS;
//long motorTimer = 0, getImuDataTimer = 0, millisNew = 0; //millisOld = 0,
//////////////////////
// Stepper motor //
//////////////////////
int stepPin = 4;
int stepPinState = LOW;
int dirPin = 2;
int dirPinState = HIGH;
unsigned long millisOld1 = 0;
unsigned long millisOld2 = 0;
long motorTimer = 1; // in milliseconds
long getImuDataTimer = 10; // in milliseconds
double maxPosition = 4100;
double stepsMoved = 0;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class WiFiHardware {
public:
WiFiHardware() {};
void init() {
// do your initialization here. this probably includes TCP server/client setup
client.connect(server, 11411);
}
// read a byte from the serial port. -1 = failure
int read() {
// implement this method so that it reads a byte from the TCP connection and returns it
// you may return -1 is there is an error; for example if the TCP connection is not open
return client.read(); //will return -1 when it will works
}
// write data to the connection to ROS
void write(uint8_t* data, int length) {
// implement this so that it takes the arguments and writes or prints them to the TCP connection
for(int i=0; i<length; i++)
client.write(data[i]);
}
// returns milliseconds since start of program
unsigned long time() {
return millis(); // easy; did this one for you
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int i;
void chatterCallback(const std_msgs::String& msg) {
i = atoi(msg.data);
// s.write(i);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setupWiFi()
{
// WIFI setup
WiFi.begin(ssid, password);
Serial.print("\nConnecting to "); Serial.println(ssid);
uint8_t i = 0;
while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500);
if(i == 21){
Serial.print("Could not connect to"); Serial.println(ssid);
while(1) delay(500);
}
Serial.print("Ready! Use ");
Serial.print(WiFi.localIP());
Serial.println(" to access client");
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ros::Subscriber<std_msgs::String> sub("message", &chatterCallback);
ros::Publisher pub("imu_data/", &imu_msg);
ros::NodeHandle_<WiFiHardware> nh;
void setup() {
// set the digital pins as outputs
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
Serial.begin(57600);
setupWiFi();
// I2C connection IMUs
Wire.begin(I2C_SDA, I2C_SCL);
I2Cbno.begin(I2C_SDA, I2C_SCL, 400000);
bno_master.begin();
bno_slave.begin();
// get imu calibrations
uint8_t system, gyro, accel, mg = 0;
bno_master.getCalibration(&system, &gyro, &accel, &mg);
bno_slave.getCalibration(&system, &gyro, &accel, &mg);
bno_master.setExtCrystalUse(true);
bno_slave.setExtCrystalUse(true);
nh.initNode();
nh.advertise(pub);
}
/////////////////////////////
/// GET IMU DATA FUNCTION ///
/////////////////////////////
int get_imu_data(){
imu::Vector<3> Euler_s = bno_slave.getVector(Adafruit_BNO055::VECTOR_EULER); // 100 Hz capacity by BNO055 // IF I COMMENT THIS LINE OUT AND SET VARIABLES BELOW TO SET VALUES, MY MOTOR RUNS PERFECTLY
// Euler
float ex_s = Euler_s.x();
float ey_s = Euler_s.y();
float ez_s = Euler_s.z();
// putting data into string since adding accel, gyro, and both imu data becomes too cumbersome for rosserial buffer size. String is better for speed of data
String data = String(ex_s) + "," + String(ey_s) + "," + String(ez_s) + "!";
int length_data = data.indexOf("!") + 1;
char data_final[length_data + 1];
data.toCharArray(data_final, length_data + 1);
imu_msg.data = data_final;
pub.publish(&imu_msg);
nh.spinOnce();
Serial.println(ey_s);
return ey_s; // ex_s, ey_s, ez_s
}
/////////////////////////////
// MAIN LOOP //
/////////////////////////////
void loop() {
unsigned long currentMillis = millis();
//////////////////
// GET IMU DATA //
//////////////////
if(currentMillis - millisOld2 >= getImuDataTimer)
{
ey_s = get_imu_data();
Serial.print(ey_s);
}
////////////////
// MOVE MOTOR //
////////////////
// later, the direction will depend on the output of ey_s
if((dirPinState == HIGH) && (currentMillis - millisOld1 >= motorTimer))
{
if(stepsMoved <= maxPosition)
{
digitalWrite(dirPin, dirPinState);
millisOld1 = currentMillis; // update time
stepsMoved += 5;
for(int i =0; i<=5; i++)
{
digitalWrite(stepPin, HIGH);
delayMicroseconds(1200); // constant speed
digitalWrite(stepPin, LOW);
}
Serial.println(stepsMoved); // checking
}
else if(stepsMoved > maxPosition)
{
dirPinState = LOW;
millisOld1 = currentMillis; // update time
stepsMoved = 0;
}
}
if((dirPinState == LOW) && (currentMillis - millisOld1 >= motorTimer))
{
if(stepsMoved <= maxPosition)
{
digitalWrite(dirPin, dirPinState);
millisOld1 = currentMillis; // update time
stepsMoved += 5;
for(int i =0; i<=5; i++)
{
digitalWrite(stepPin, HIGH);
delayMicroseconds(1200); // constant speed
digitalWrite(stepPin, LOW);
}
Serial.println(stepsMoved); // checking
}
else if(stepsMoved > maxPosition)
{
dirPinState = HIGH;
millisOld1 = currentMillis; // update time
stepsMoved = 0;
}
}
}
I have tried the AccelStepper.h library but not getting the outputs desired in terms of position control and speed updates.
Arduino's all-in-one loop() is not the correct architecture for controlling real-time systems. Motor control requires rather accurate timing - e.g. looks like you wish to update motor control output with a frequency of 833 Hz (from the 1.2 ms delay) which should then be fairly accurate and stable.
Unfortunately you're not getting anywhere near this, as you're doing a bunch of non-critical stuff in each loop which potentially takes a very long (and undeterministic) amount of time - waiting for the IMU to give you a sample, printing to the serial port, talking to some ROS component, etc. Meanwhile the real-time critical control signal to your motor is waiting for all this to finish before it can do its work. Note that printing a few lines to the serial could already take dozens of milliseconds, so your delayMicroseconds(1200); is analogous to measuring a cut with a caliper and then making the cut with an axe with your eyes closed.
A real-time critical process should execute in its own thread which has higher priority than the non-real-time critical stuff. In your case it should probably run off a timer with a 1.2 ms period. The timer handler should execute with higher priority than all the other stuff, calculate desired output to motor using last received sensor input (i.e. don't go asking the IMU for a fresh reading when it's time to move the motor) and exit.
Then you can run all the other stuff from the loop() in idle priority which simply gets pre-empted when the motor control does its work.
Depending on how critical the accurate timing of IMU input is, you may want to run this also in a separate thread with a priority somewhere between the motor control interrupt and idle (remember to yield some CPU cycles to loop() or it'll starve).
The size of my buffer is 4096 and I want to fill the buffer with the adc values that are read.
#define ADC_BUF_LEN 4096
uint16_t adc_buf[ADC_BUF_LEN];
I am using this function to start the reading process of the ADC using DMA
HAL_ADC_Start_DMA(&hadc2, (uint32_t*)adc_buf, ADC_BUF_LEN);
Here are my configurations for the ADC
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV6;
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc2.Init.ContinuousConvMode = ENABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 1;
hadc2.Init.DMAContinuousRequests = ENABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
This my DMA configuration
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
}
These are my interrupt functions. I set a toggle breakpoint on the first interrupt and when I debug, the LED does not turn on which suggests that the DMA isn't working?
/* USER CODE BEGIN 4 */
//Called when first half of buffer is filled
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) {
//HAL_ADC_GetValue(&hadc2);
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
}
//Called when buffer is completely filled
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);
}
I set the prescaled to be divided by 6 if this information helps.
Please give me some advice!
Thank you in advance.
I've recently purchased this: http://redbearlab.com/bleshield/
I've connected it to my Arduino and I'm trying to run the very first test program that they tell me to run which is the BLE Controller sketch. I've connected it and resolved some original compile errors that I initially got, and now it will upload. When I upload it, my iPhone is unresponsive to the shield. I'm trying to figure out if the problem is in the code or if it's a problem with the shield itself. If it's the code, how could I fix the code? I'm relatively new to Arduino and completely new to making it work with Bluetooth. Here's the entire sketch that the guide told me to download from Github.
BLEControllerSketch.ino
/*
Copyright (c) 2012, 2013 RedBearLab
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <Servo.h>
#include <SPI.h>
#include <EEPROM.h>
#include <boards.h>
#include <RBL_nRF8001.h>
#include "Boards.h"
#define PROTOCOL_MAJOR_VERSION 0 //
#define PROTOCOL_MINOR_VERSION 0 //
#define PROTOCOL_BUGFIX_VERSION 2 // bugfix
#define PIN_CAPABILITY_NONE 0x00
#define PIN_CAPABILITY_DIGITAL 0x01
#define PIN_CAPABILITY_ANALOG 0x02
#define PIN_CAPABILITY_PWM 0x04
#define PIN_CAPABILITY_SERVO 0x08
#define PIN_CAPABILITY_I2C 0x10
// pin modes
//#define INPUT 0x00 // defined in wiring.h
//#define OUTPUT 0x01 // defined in wiring.h
#define ANALOG 0x02 // analog pin in analogInput mode
#define PWM 0x03 // digital pin in PWM output mode
#define SERVO 0x04 // digital pin in Servo output mode
byte pin_mode[TOTAL_PINS];
byte pin_state[TOTAL_PINS];
byte pin_pwm[TOTAL_PINS];
byte pin_servo[TOTAL_PINS];
Servo servos[MAX_SERVOS];
void setup()
{
Serial.begin(57600);
Serial.println("BLE Arduino Slave");
/* Default all to digital input */
for (int pin = 0; pin < TOTAL_PINS; pin++)
{
// Set pin to input with internal pull up
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
// Save pin mode and state
pin_mode[pin] = INPUT;
pin_state[pin] = LOW;
}
// Default pins set to 9 and 8 for REQN and RDYN
// Set your REQN and RDYN here before ble_begin() if you need
//ble_set_pins(3, 2);
// Set your BLE Shield name here, max. length 10
//ble_set_name("My Name");
// Init. and start BLE library.
ble_begin();
}
static byte buf_len = 0;
void ble_write_string(byte *bytes, uint8_t len)
{
if (buf_len + len > 20)
{
for (int j = 0; j < 15000; j++)
ble_do_events();
buf_len = 0;
}
for (int j = 0; j < len; j++)
{
ble_write(bytes[j]);
buf_len++;
}
if (buf_len == 20)
{
for (int j = 0; j < 15000; j++)
ble_do_events();
buf_len = 0;
}
}
byte reportDigitalInput()
{
if (!ble_connected())
return 0;
static byte pin = 0;
byte report = 0;
if (!IS_PIN_DIGITAL(pin))
{
pin++;
if (pin >= TOTAL_PINS)
pin = 0;
return 0;
}
if (pin_mode[pin] == INPUT)
{
byte current_state = digitalRead(pin);
if (pin_state[pin] != current_state)
{
pin_state[pin] = current_state;
byte buf[] = {'G', pin, INPUT, current_state};
ble_write_string(buf, 4);
report = 1;
}
}
pin++;
if (pin >= TOTAL_PINS)
pin = 0;
return report;
}
void reportPinCapability(byte pin)
{
byte buf[] = {'P', pin, 0x00};
byte pin_cap = 0;
if (IS_PIN_DIGITAL(pin))
pin_cap |= PIN_CAPABILITY_DIGITAL;
if (IS_PIN_ANALOG(pin))
pin_cap |= PIN_CAPABILITY_ANALOG;
if (IS_PIN_PWM(pin))
pin_cap |= PIN_CAPABILITY_PWM;
if (IS_PIN_SERVO(pin))
pin_cap |= PIN_CAPABILITY_SERVO;
buf[2] = pin_cap;
ble_write_string(buf, 3);
}
void reportPinServoData(byte pin)
{
// if (IS_PIN_SERVO(pin))
// servos[PIN_TO_SERVO(pin)].write(value);
// pin_servo[pin] = value;
byte value = pin_servo[pin];
byte mode = pin_mode[pin];
byte buf[] = {'G', pin, mode, value};
ble_write_string(buf, 4);
}
byte reportPinAnalogData()
{
if (!ble_connected())
return 0;
static byte pin = 0;
byte report = 0;
if (!IS_PIN_DIGITAL(pin))
{
pin++;
if (pin >= TOTAL_PINS)
pin = 0;
return 0;
}
if (pin_mode[pin] == ANALOG)
{
uint16_t value = analogRead(pin);
byte value_lo = value;
byte value_hi = value>>8;
byte mode = pin_mode[pin];
mode = (value_hi << 4) | mode;
byte buf[] = {'G', pin, mode, value_lo};
ble_write_string(buf, 4);
}
pin++;
if (pin >= TOTAL_PINS)
pin = 0;
return report;
}
void reportPinDigitalData(byte pin)
{
byte state = digitalRead(pin);
byte mode = pin_mode[pin];
byte buf[] = {'G', pin, mode, state};
ble_write_string(buf, 4);
}
void reportPinPWMData(byte pin)
{
byte value = pin_pwm[pin];
byte mode = pin_mode[pin];
byte buf[] = {'G', pin, mode, value};
ble_write_string(buf, 4);
}
void sendCustomData(uint8_t *buf, uint8_t len)
{
uint8_t data[20] = "Z";
memcpy(&data[1], buf, len);
ble_write_string(data, len+1);
}
byte queryDone = false;
void loop()
{
while(ble_available())
{
byte cmd;
cmd = ble_read();
Serial.write(cmd);
// Parse data here
switch (cmd)
{
case 'V': // query protocol version
{
byte buf[] = {'V', 0x00, 0x00, 0x01};
ble_write_string(buf, 4);
}
break;
case 'C': // query board total pin count
{
byte buf[2];
buf[0] = 'C';
buf[1] = TOTAL_PINS;
ble_write_string(buf, 2);
}
break;
case 'M': // query pin mode
{
byte pin = ble_read();
byte buf[] = {'M', pin, pin_mode[pin]}; // report pin mode
ble_write_string(buf, 3);
}
break;
case 'S': // set pin mode
{
byte pin = ble_read();
byte mode = ble_read();
if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached())
servos[PIN_TO_SERVO(pin)].detach();
/* ToDo: check the mode is in its capability or not */
/* assume always ok */
if (mode != pin_mode[pin])
{
pinMode(pin, mode);
pin_mode[pin] = mode;
if (mode == OUTPUT)
{
digitalWrite(pin, LOW);
pin_state[pin] = LOW;
}
else if (mode == INPUT)
{
digitalWrite(pin, HIGH);
pin_state[pin] = HIGH;
}
else if (mode == ANALOG)
{
if (IS_PIN_ANALOG(pin)) {
if (IS_PIN_DIGITAL(pin)) {
pinMode(PIN_TO_DIGITAL(pin), LOW);
}
}
}
else if (mode == PWM)
{
if (IS_PIN_PWM(pin))
{
pinMode(PIN_TO_PWM(pin), OUTPUT);
analogWrite(PIN_TO_PWM(pin), 0);
pin_pwm[pin] = 0;
pin_mode[pin] = PWM;
}
}
else if (mode == SERVO)
{
if (IS_PIN_SERVO(pin))
{
pin_servo[pin] = 0;
pin_mode[pin] = SERVO;
if (!servos[PIN_TO_SERVO(pin)].attached())
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
}
}
}
// if (mode == ANALOG)
// reportPinAnalogData(pin);
if ( (mode == INPUT) || (mode == OUTPUT) )
reportPinDigitalData(pin);
else if (mode == PWM)
reportPinPWMData(pin);
else if (mode == SERVO)
reportPinServoData(pin);
}
break;
case 'G': // query pin data
{
byte pin = ble_read();
reportPinDigitalData(pin);
}
break;
case 'T': // set pin digital state
{
byte pin = ble_read();
byte state = ble_read();
digitalWrite(pin, state);
reportPinDigitalData(pin);
}
break;
case 'N': // set PWM
{
byte pin = ble_read();
byte value = ble_read();
analogWrite(PIN_TO_PWM(pin), value);
pin_pwm[pin] = value;
reportPinPWMData(pin);
}
break;
case 'O': // set Servo
{
byte pin = ble_read();
byte value = ble_read();
if (IS_PIN_SERVO(pin))
servos[PIN_TO_SERVO(pin)].write(value);
pin_servo[pin] = value;
reportPinServoData(pin);
}
break;
case 'A': // query all pin status
for (int pin = 0; pin < TOTAL_PINS; pin++)
{
reportPinCapability(pin);
if ( (pin_mode[pin] == INPUT) || (pin_mode[pin] == OUTPUT) )
reportPinDigitalData(pin);
else if (pin_mode[pin] == PWM)
reportPinPWMData(pin);
else if (pin_mode[pin] == SERVO)
reportPinServoData(pin);
}
queryDone = true;
{
uint8_t str[] = "ABC";
sendCustomData(str, 3);
}
break;
case 'P': // query pin capability
{
byte pin = ble_read();
reportPinCapability(pin);
}
break;
case 'Z':
{
byte len = ble_read();
byte buf[len];
for (int i=0;i<len;i++)
buf[i] = ble_read();
Serial.println("->");
Serial.print("Received: ");
Serial.print(len);
Serial.println(" byte(s)");
Serial.print(" Hex: ");
for (int i=0;i<len;i++)
Serial.print(buf[i], HEX);
Serial.println();
}
}
// send out any outstanding data
ble_do_events();
buf_len = 0;
return; // only do this task in this loop
}
// process text data
if (Serial.available())
{
byte d = 'Z';
ble_write(d);
delay(5);
while(Serial.available())
{
d = Serial.read();
ble_write(d);
}
ble_do_events();
buf_len = 0;
return;
}
// No input data, no commands, process analog data
if (!ble_connected())
queryDone = false; // reset query state
if (queryDone) // only report data after the query state
{
byte input_data_pending = reportDigitalInput();
if (input_data_pending)
{
ble_do_events();
buf_len = 0;
return; // only do this task in this loop
}
reportPinAnalogData();
ble_do_events();
buf_len = 0;
return;
}
ble_do_events();
buf_len = 0;
}
Any and all help is greatly appreciated.
I've been working with these quite a bit in the last 8 months, so I'll do what I can to help. I don't have the reputation to comment and ask for clarification on specific things, so I'm just gonna try to cover everything I can.
Let's first lay out a few things:
Because your sketch uploaded I'm assuming that you have added all of the necessary libraries to Arduino. If you haven't, I don't know why it is uploading, but be sure to do that.
The problem almost certainly won't be with the Arduino code. I ran the code you provided, as well as the sketch provided by RBL (Red Bear Lab) that is on my computer. I was able to connect to my iPhone using both sketches.
I'm going to lay out everything I think could potentially be the source of the problem:
Make sure that all of your header pins (you should have a bunch of headers sticking out of the board in rows of 3 next to the digital pins) are connected correctly, as RBL shows in their instructions. If you want me to provide a picture of mine I can do that.
Make sure that the white power light is on on your shield. If it isn't, power isn't getting to the shield itself.
Be sure that you actually have bluetooth enabled on your phone.
You didn't mention that you downloaded the app. Be sure to do that (it is called "BLE Controller" by RedBear), as you cannot connect to the iPhone without the app (Apple's bluetooth menu will not show the BLE shield).
If you have downloaded the app, be sure that you have selected the correct setting from the choices using the button on the top left of the screen (3 lines on top of each other). For the sketch you provided, you should select BLE Controller.
If you have tried everything and nothing else is working, try one of the other sketches provided by RBL, such as SimpleChat. This uses the serial monitor on Arduino to communicate back and forth with the iPhone. If this doesn't work, upload a picture of your specific shield (the top of it) so I can take a look at it. Best of luck.
I'm having trouble with my XBee's printing out to the monitor a simple statement, within the void setup(), as shown in my program below.
It prints the GPS and various sensor data, but it skips the whole introductory sentences. Whenever I open the arduino serial monitor, with the board plugged into my computer, it works fine.
Any suggestions? I'm at a lost!
Thanks :)
// Temperature Sensor data, Air Quality, and GPS data update XBEE
//CSV format for user interpretation
//Last updated 11/5/14
//Amy Laguna
#include <Adafruit_GPS.h>
#include <math.h>
#include <SoftwareSerial.h>
SoftwareSerial XBee(2, 3);
SoftwareSerial mySerial(8, 7);
//Read temperature sensor on A1
int tempPin = 1;
//Read CO sensor on A0
int coPin = 0;
//Read Oxygen sensor on A2
int opin = 2;
//GPS setup
Adafruit_GPS GPS(&mySerial);
//Use to debug
//SET to 'fale' to turn off echoing the GPS data to Serial
//Set to 'true' to debug and listen to raw GPS data
#define GPSECHO false
// this keeps track of whether we're using the interrupt
boolean usingInterrupt = false;
void useInterrupt(boolean);
void setup()
{
// connect at 115200 so we can read the GPS fast enough and echo without dropping chars
XBee.begin(115200);
Serial.begin(115200);
delay(5000);
XBee.println("Vehicle GPS, Temperature, and Air Quality Data!");
delay(2000);
XBee.println("Note: Elevation in Pensacola Florida: ~ 31 m (102 ft)");
XBee.println();
XBee.println("\n Date: Time: Fix: Location: Speed (mph): Elevation: CO: O2: Temperature: ");
// 9600 NMEA is the default baud rate for Adafruit MTK GPS's
GPS.begin(9600);
// RMC (recommended minimum) and GGA (fix data) including altitude
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
// Set the update rate
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate
// For the parsing code to work nicely and have time to sort thru the data, and
// print it out we don't suggest using anything higher than 1 Hz
useInterrupt(true);
delay(1500);
}
// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
char c = GPS.read();
// if you want to debug, this is a good time to do it!
#ifdef UDR0
if (GPSECHO)
if (c) UDR0 = c;
#endif
}
void useInterrupt(boolean v) {
if (v) {
// Timer0 is already used for millis() - we'll just interrupt somewhere
// in the middle and call the "Compare A" function above
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
usingInterrupt = true;
} else {
// do not call the interrupt function COMPA anymore
TIMSK0 &= ~_BV(OCIE0A);
usingInterrupt = false;
}
}
uint32_t timer = millis();
void loop() // run over and over again
{
if (! usingInterrupt) {
// read data from the GPS in the 'main loop'
char c = GPS.read();
// if you want to debug, this is a good time to do it!
if (GPSECHO)
if (c) XBee.print(c);
}
// if a sentence is received, we can check the checksum, parse it...
if (GPS.newNMEAreceived()) {
if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false
return; // we can fail to parse a sentence in which case we should just wait for another
}
// if millis() or timer wraps around, we'll just reset it
if (timer > millis()) timer = millis();
// approximately every 2 seconds or so, print out the current stats
if (millis() - timer > 2000) {
timer = millis(); // reset the timer
PrintGPS(); //Print GPS readings
PrintAirQuality(); //Print CO and Temperature readings
}
}
void PrintGPS()
{
//Print Date, Time, Fix
XBee.print("\n");
XBee.print(GPS.month, DEC); XBee.print('/');
XBee.print(GPS.day, DEC); XBee.print("/20");
XBee.print(GPS.year, DEC);
XBee.print(" , ");
XBee.print(GPS.hour, DEC); XBee.print(':');
XBee.print(GPS.minute, DEC); XBee.print(':');
XBee.print(GPS.seconds, DEC);
}
Maybe try a longer delay before the XBee.println() statements. If the radio modules haven't associated yet, they won't be ready for you to start sending data through them.
Alternatively, wait until the first call to PrintGPS() and send it then:
void PrintGPS()
{
static int first_time = 1;
if (first_time) {
print_headers();
first_time = 0;
}
//Print Date, Time, Fix
...
I have some code below that has a slight bug that I don't know how to fix. Essentially what is happening is my high ISR is running twice after the the flag is set. It only runs twice and is consistent. The subroutine should run only once because the flag is set when the input on RB changes, and the routine runs twice after one change to RB's input. The testing was conducted in MPLAB v8.6 using the workbook feature.
#include <p18f4550.h>
#include <stdio.h>
void init(void)
{
RCONbits.IPEN =1; //allows priority
INTCONbits.GIE = 1; //allows interrupts
INTCONbits.PEIE = 1; //allows peripheral interrupts
INTCONbits.RBIF = 0; //sets flag to not on
INTCONbits.RBIE = 1; //enables RB interrupts
INTCON2bits.RBPU = 1; //enable pull up resistors
INTCON2bits.RBIP = 1; //RB interrupts is high priority
PORTB = 0x00;
TRISBbits.RB7 = 1; //enable RB7 as an input so we can throw interrupts when it changes.
}
#pragma code
#pragma interrupt high_isr
void high_isr(void)
{
if(INTCONbits.RBIF == 1)
{
INTCONbits.RBIF = 0;
//stuff
}
}
#pragma code
#pragma code high_isr_entry = 0x08
void high_isr_entry(void)
{_asm goto high_isr _endasm}
void main(void)
{
init();
while(1);
}
The RB7 interrupt flag is set based on a compare of the last latched value and the current state of the pin. In the datasheet it says "The pins are compared with the old value latched on the last read of PORTB. The 'mismatch' outputs of RB7:RB4 are ORed together to generate the RB Port Change Interrupt with Flag bit."
To clear the mismatch condition the datasheet goes on to say "Any read or write of PORTB (except with the
MOVFF (ANY), PORTB instruction). This will end the mismatch condition."
You then wait one Tcy (execute a nop instruction) and then clear the flag. This is documented on page 116 of the datasheet.
So the simplest fix in this scenario is in the interrupt routine declare a dummy variable and set it to RB7 like this:
#pragma interrupt high_isr
void high_isr(void)
{
unsigned short dummy;
if(INTCONbits.RBIF == 1)
{
dummy = PORTBbits.RB7; // Perform read before clearing flag
Nop();
INTCONbits.RBIF = 0;
// rest of your routine here
// ...