I'm trying to set up my STM32F407-Discovery board to read multiple ADC channels from ADC1 using the DMA controller. I can easily read the analog value one at a time without using DMA, but as soon as I enable DMA for the ADC, ADC1->DR is always 0, and adc_vals is filled with zeros. Furthermore, it hangs on while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));.
EDIT: it would appear DMA_GetCmdStatus is returning DISABLED. Any ideas?
Is there a way to start the ADC or something that I'm missing?
//setup adc1: in1,2,3,8,9,15
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //adc1 on the apb2 peripheral bus
ADC_InitTypeDef adc;
ADC_DeInit(); //set adc to default state
adc.ADC_DataAlign = ADC_DataAlign_Right;
adc.ADC_Resolution = ADC_Resolution_12b;//12 bit = 4096
adc.ADC_ContinuousConvMode = ENABLE;
adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
adc.ADC_NbrOfConversion = NUM_ADC;
adc.ADC_ScanConvMode = ENABLE;
ADC_Init(ADC1,&adc);
ADC_DMACmd(ADC1, ENABLE); //enable adc for dma. When this line is removed, I see data on ADC1->DR
ADC_Cmd(ADC1,ENABLE);
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_144Cycles);//1:1710, 0
//ADC_RegularChannelConfig(ADC1,ADC_Channel_2,2,ADC_SampleTime_144Cycles);//2:1710, 0
//ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_144Cycles);//3:1710, 0
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,4,ADC_SampleTime_144Cycles);//8:3520
ADC_RegularChannelConfig(ADC1,ADC_Channel_9,5,ADC_SampleTime_144Cycles);//9:1000
//ADC_RegularChannelConfig(ADC1,ADC_Channel_15,6,ADC_SampleTime_144Cycles);//15:3920
//DMA for multiple adc channels:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); //dma1 clock enable
DMA_InitTypeDef dma;
DMA_DeInit(DMA2_Stream0); //reset DMA2 stream 0 to default values
dma.DMA_Channel = DMA_Channel_0;
dma.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
dma.DMA_Memory0BaseAddr = (uint32_t)&adc_vals[0];
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = NUM_ADC;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_Priority = DMA_Priority_High;
dma.DMA_FIFOMode = DMA_FIFOMode_Disable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &dma);
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE); //Enable DMA Stream Half / Transfer Complete interrupt
DMA_Cmd(DMA2_Stream0, ENABLE); //DMA2_Stream0 enable
//dma transfer complete interrupt:
NVIC_InitTypeDef nvic;
//Enable DMA1 channel IRQ Channel
nvic.NVIC_IRQChannel = DMA2_Stream0_IRQn;
nvic.NVIC_IRQChannelPreemptionPriority = 0;
nvic.NVIC_IRQChannelSubPriority = 0;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);
ADC_SoftwareStartConv(ADC1);//Start the adc conversion
At least you can try:
change DMA_PeripheralInc to enable
use ADC_DMARequestAfterLastTransferCmd(ADC, Enable); for dma request after group conversion.
init ADC_CommonInitTypeDef
init GPIO, if not
Moreover enabling ADC before all the configurations is strange.
In my opinion the best way is to copy-paste "ADC_DualModeRegulSimu"example from standard peripherals library. It contains beautiful code exactly for your purpose.
There were a number of errors. Here's my working code for anybody else having the same trouble:
//DMA for multiple adc channels:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //ADC1 on APB2 peripheral bus
DMA_InitTypeDef dma; //dma2/stream0/channel0
dma.DMA_Channel = DMA_Channel_0;
dma.DMA_Memory0BaseAddr = (uint32_t)&adcVal;
dma.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = 6;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_Priority = DMA_Priority_High;
dma.DMA_FIFOMode = DMA_FIFOMode_Enable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &dma);
DMA_Cmd(DMA2_Stream0, ENABLE); //dMA2_Stream0 enable
//analog inputs: PA1,2,3, PC5, PB0,1
gpio.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
gpio.GPIO_Mode = GPIO_Mode_AN;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpio);
gpio.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOC, &gpio);
gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &gpio);
//ADC common init
ADC_CommonInitTypeDef adcCommon;
adcCommon.ADC_Mode = ADC_Mode_Independent;
adcCommon.ADC_Prescaler = ADC_Prescaler_Div2;
adcCommon.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
adcCommon.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&adcCommon);
//setup adc1: in1,2,3,8,9,15
ADC_InitTypeDef adc;
ADC_DeInit(); //set adc to default state
adc.ADC_DataAlign = ADC_DataAlign_Right; //mask 0b 00001111 11111111
adc.ADC_Resolution = ADC_Resolution_12b;//12 bit = 4096
adc.ADC_ContinuousConvMode = ENABLE; //continuous: constantly converting data - can always read register
adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;//external trigger conversion (?)
adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
adc.ADC_NbrOfConversion = 6;
adc.ADC_ScanConvMode = ENABLE;//single/multichannel
ADC_Init(ADC1,&adc);
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC1,ADC_Channel_2,2,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,4,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_9,5,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_15,6,ADC_SampleTime_56Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); //single adc repeated
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1,ENABLE);
Thanks for the code ethan, made minor mod to fit my case and to work as a general function.
volatile uint16_t adcVal[6];
void Setup_DMA_ADC( void )
{
GPIO_InitTypeDef gpio;
//DMA for multiple adc channels:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //ADC1 on APB2 peripheral bus
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
DMA_InitTypeDef dma; //dma2/stream0/channel0
dma.DMA_Channel = DMA_Channel_0;
dma.DMA_Memory0BaseAddr = (uint32_t) &adcVal[0];
dma.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = 6;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_Priority = DMA_Priority_High;
dma.DMA_FIFOMode = DMA_FIFOMode_Enable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &dma);
DMA_Cmd(DMA2_Stream0, ENABLE); //dMA2_Stream0 enable
//analog inputs: PA1,2,3, PC5, PB0,1
GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
gpio.GPIO_Mode = GPIO_Mode_AN;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpio);
gpio.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOC, &gpio);
gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &gpio);
//ADC common init
ADC_CommonInitTypeDef adcCommon;
adcCommon.ADC_Mode = ADC_Mode_Independent;
adcCommon.ADC_Prescaler = ADC_Prescaler_Div2;
adcCommon.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
adcCommon.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&adcCommon);
//setup adc1: in1,2,3,8,9,15
ADC_InitTypeDef adc;
ADC_DeInit(); //set adc to default state
adc.ADC_DataAlign = ADC_DataAlign_Right; //mask 0b 00001111 11111111
adc.ADC_Resolution = ADC_Resolution_12b;//12 bit = 4096
adc.ADC_ContinuousConvMode = ENABLE; //continuous: constantly converting data - can always read register
adc.ADC_ExternalTrigConv = DISABLE;//ADC_ExternalTrigConv_T1_CC1;//external trigger conversion (?)
adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
adc.ADC_NbrOfConversion = 6;
adc.ADC_ScanConvMode = ENABLE;//single/multichannel
ADC_Init(ADC1,&adc);
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_2,2,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,4,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_9,5,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_15,6,ADC_SampleTime_56Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); //single adc repeated
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1,ENABLE);
// Start ADC conversion
ADC_SoftwareStartConv(ADC1);
return;
}
Related
I'm new to the world of programming and Arduinos and I am not really sure how to solve this error message. Been researching for answers for quite some time now and I still cannot find an answer as to how to solve this error message. There are error messages on the Arduino IDE and suggestions are also given but I'm not sure how to use those suggestions. I am using an Arduino Pro Micro for this project.
#include <Joystick.h>
//initializing variables
int R2 = 2;
int L3 = 3;
//Define input pins
#define joyX A0
#define joyY A1
#define joyX A2
#define joyY A3
#define joyButton1 2
#define joyButton2 3
//Joystick(Joystick HID ID, Joytstick Type, Button Count, Hat Switch Count, Include X, Include Y, Include Z,
//Include Rx, Include Ry, Include Rudder, Include Throttle, Include Accelerator, Include Break, Include Steering
Joystick_Joystick(0x04, JOYSTICK_TYPE_JOYSTICK, 3, 0, true, true, false, false, false, false, false, false, false, false);
//initializing bool constant
const bool initAutoSendState = true;
//initializing axis
int xAxis_ = 0;
int yAxis_ = 0;
//Set Button Default State
int lastButtonState =0;
int lastButtonState =0;
void setup() {
pinMode(joyButton1, INPUT_PULLUP);
pinMode(joyButton2, INPUT_PULLUP):
Joystick.begin();
}
void loop() {
//Axis Runtime
xAxis_ = analogRead(joyX);
xAxis_ = map (xAxis,0,1023,0,255);
Joystick.setXAxis(xAxis_);
yAxis_ = analogRead(joyY);
yAxis_ = map (yAxis,0,1023,0,255);
Joystick.setYAxis(yAxis_);
//Button State setup
int currentButton1State = !digitalRead(joyButton1);
if (currentButton1State != lastButton1State) {
Joystick.setButton (0, currentButton1State);
lastButton1State = currentButton1State;
}
int currentButton2State = !digitalRead(joyButton2);
if (currentButton2State != lastButton2State) {
Joystick.setButton (0, currentButton2State);
lastButton2State = currentButton2State;
}
//Poll Delay/Debounce
delay(500);
}
How can the STM32F103C8 be configured to run with internal RC oscillator / HSI & PLL, i.e. without external crystal oscillator (as present on the "blue pill" board) with the Arduino framework in PlatformIO?
https://docs.platformio.org/en/latest/boards/ststm32/bluepill_f103c8.html
https://docs.platformio.org/en/latest/boards/ststm32/genericSTM32F103C8.html
https://docs.platformio.org/en/latest/frameworks/arduino.html
platformio.ini:
[env:bluepill_f103c8]
platform = ststm32
board = bluepill_f103c8
#board = genericSTM32F103C8
#board_build.mcu = stm32f103c8t6
#board_build.f_cpu = 72000000L
framework = arduino
lib_deps = olikraus/U8g2 # ^2.28.7
upload_protocol = stlink
I dug around a bit in the PlatformIO directory.
The following paths are for "generic":
C:\Users\<user>\.platformio\platforms\ststm32\boards\genericSTM32F103C8.json
C:\Users\<user>\.platformio\packages\framework-arduinoststm32\variants\Generic_F103Cx\variant.cpp
Define your own system clock configuration in e.g. your main.cpp:
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInit;
/* Initializes the CPU, AHB and APB busses clocks */
// RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
// RCC_OscInitStruct.HSEState = RCC_HSE_ON;
// RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
// RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
while (1);
}
/* Initializes the CPU, AHB and APB busses clocks */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
while (1);
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC ;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
while (1);
}
}
The ini then is:
[env:bluepill_f103c8]
platform = ststm32
board = genericSTM32F103C8
framework = arduino
upload_protocol = stlink
lib_deps = olikraus/U8g2 # ^2.28.7
I'd recommend renaming the env to avoid confusion.
I have not yet verified the actual clock speed.
It should run at 36 MHz (8 MHz/2*9). The ini then needs `board_build.f_cpu = 36000000L`
I know there is #use rs232 command to activate it,
but i want to know how to set registers individually to activate rs232
i'm using PIC18f13k22.
I did like this:
INTCON = 0xc2;
IPR1 = 0x7f;
PIE1 = 0x20;
PIR1 = 0x10;
BAUDCON = 0x48;
RCSTA = 0x90;
TXSTA = 0xA6;
SPBRG = 0x82;
SPBRGH = 0x06;
I looked up PIC18f13k22 datasheet, and found related registers, and set like that.
and didn't work.
need help!
thanks
Here is a complete code that builds with Microchip MPLABX and XC8 v2.30:
/*
* File: main.c
* Author: dan1138
* Compiler: XC8 v2.30
*
* Created on October 6, 2020, 1:41 PM
*/
#pragma config FOSC = IRC, PLLEN = OFF, PCLKEN = ON, FCMEN = OFF, IESO = OFF
#pragma config PWRTEN = OFF, BOREN = SBORDIS, BORV = 19, WDTEN = OFF
#pragma config WDTPS = 32768, HFOFST = ON, MCLRE = ON, STVREN = ON, LVP = OFF
#pragma config BBSIZ = OFF, XINST = OFF, DEBUG = OFF, CP0 = OFF, CP1 = OFF
#pragma config CPB = OFF, CPD = OFF, WRT0 = OFF, WRT1 = OFF, WRTC = OFF
#pragma config WRTB = OFF, WRTD = OFF, EBTR0 = OFF, EBTR1 = OFF, EBTRB = OFF
#include <xc.h>
#include <stdio.h>
void putch(char txData)
{
if(1 == RCSTAbits.OERR)
{
RCSTAbits.CREN = 0;
RCSTAbits.CREN = 1;
}
while(0 == PIR1bits.TXIF)
{
}
TXREG = txData;
}
void main(void)
{
OSCCON = 0x60;
OSCCON2 = 0x04;
OSCTUNE = 0x00;
LATA = 0x00;
LATB = 0x00;
LATC = 0x00;
TRISA = 0x37;
TRISB = 0x70;
TRISC = 0xFF;
ANSEL = 0xFF;
ANSELH = 0x07;
WPUB = 0x00;
WPUA = 0x00;
INTCON2bits.nRBPU = 1;
BAUDCON = 0x08;
RCSTA = 0x90;
TXSTA = 0x24;
SPBRG = 0xCF;
SPBRGH = 0x00;
PIR1bits.TXIF = 0;
printf("\r\nPIC18F13K22 UART demo\r\n");
while (1)
{
}
}
The solution to your problem lies in knowing what to set the configuration word values to, and how to comprehend what information can be found in the data sheet.
I know the data sheet is dense and only documents what can be selected, but not why specific values should be chosen.
With more experience you can learn how to read data sheets and what can be useful.
As you made no effort to comment in the code you posted my code is likewise missing anything close to a useful comment.
I'm trying to send sms using huawei e173 gsm modem. Everything works fine in text mode, but I can't figure out how to send sms in pdu mode. I have tried to send simple message that will say "hellohello". This is my message format in Qt designer (which is irrelevant for this subject, I'm having problems with error 304 - invalid PDU mode parameter):
QByteArray PDUtext;
PDUtext[0] = 0x00;
PDUtext[1] = 0x11;
PDUtext[2] = 0x00;
PDUtext[3] = 0x0b; // Phone number length
PDUtext[4] = 0x91; // International
//Phone: +381 600123456 (83 61 00 21 43 65)
PDUtext[5] = 0x83;
PDUtext[6] = 0x61;
PDUtext[7] = 0x00;
PDUtext[8] = 0x21;
PDUtext[9] = 0x43;
PDUtext[10] = 0x65;
PDUtext[11] = 0x00;
PDUtext[12] = 0x00;
PDUtext[13] = 0xaa; // 4 days validity period
//E8 32 9B FD 46 97 D9 EC 37
PDUtext[14] = 0x0a; // Message length
// Message "hellohello"
PDUtext[15] = 0xe8;
PDUtext[16] = 0x32;
PDUtext[17] = 0x9b;
PDUtext[18] = 0xfd;
PDUtext[19] = 0x46;
PDUtext[20] = 0x97;
PDUtext[20] = 0xd9;
PDUtext[20] = 0xec;
PDUtext[20] = 0x37;
What is wrong with this message?
Commands look like this:
AT+CMGF=0<CR> // PDU mode
Modem > OK
AT+CMGS=20<CR> // Send with message length
>PDUtext<Ctrl+z>
Modem > +CMS ERROR: 304
There are two errors in your PDU.
1) The destination number length is incorrect
You have used 0x0B when infact you should have used 0C
2) Bytes incorrectly assigned
PDUtext[20] = 0x97;
PDUtext[20] = 0xd9;
PDUtext[20] = 0xec;
PDUtext[20] = 0x37;
Should be
PDUtext[20] = 0x97;
PDUtext[21] = 0xd9;
PDUtext[22] = 0xec;
PDUtext[23] = 0x37;
I doing a project with Arduino Uno R3 and XBee S2 transmission. I use a couple of sensors like a wireless (RF) temperature sensor, two SHT75 sensors, a 3-axis accelerometer and an illumination sensor. And after collecting the data, we use XBee (S2, API mode) to send the data to the gateway. Every round is about one second.
The first problem is the data is about 16 bytes, but the packet does not send successful every round. Sometime it works, and sometimes it doesn't, but the payload of XBee can be 60 or 70 bytes in the datasheet... But if I put the payload as some simply an integer (like 1, 2, 3), not the data from sensor, and the transmission will be stable.
After meeting the problem above, I divided the data into two packets (each with an eight bytes payload), and the first packet is very stable, but the second is very unstable. As mentioned above, if I put some number into the second packets instead of the sensing data the second packet will become stable and send successfully every round.
So I think it's the code problem, but idk where is the problem. I try to change the baud rate or increasing the delay time between the two packets. Where is the problem? The following is my code:
#include <XBee.h>
#include <i2cmaster.h>
#include <string.h>
#include <ctype.h>
#include <Sensirion.h>
#include "Wire.h"
#include "MMA845XQ.h"
**///////////////////////////// XBee setup //////////////////////////////////**
XBee xbee = XBee();
XBeeAddress64 remoteAddress = XBeeAddress64(0x00000000, 0x00000000);
ZBRxResponse zbRx = ZBRxResponse();
ZBTxStatusResponse zbTxStus = ZBTxStatusResponse();
uint8_t payload[] = {0,0,0,0,0,0,0,0,0};
uint8_t payload1[] = {0,0,0,0,0,0,0,0,0};
**///////////////////////////// Accelerometer //////////////////////////////////**
MMA845XQ accel;
**////////////////////////// SHT1 serial data and clock ////////////////////**
const byte dataPin = 2;
const byte sclkPin = 3;
Sensirion sht = Sensirion(dataPin, sclkPin);
unsigned int rawData;
float temperature;
float humidity;
byte stat;
**////////////////////////// SHT2 serial data and clock ////////////////////**
const byte dataPin1 = 4;
const byte sclkPin1 = 5;
Sensirion sht1 = Sensirion(dataPin1, sclkPin1);
unsigned int rawData1;
float temperature1;
float humidity1;
byte stat1;
**//////////////////////////// Illumination sensor ////////////////////////**
int sensorPin = A0; // Select the input pin for the potentiometer
int sensorValue = 0; // Variable to store the value coming from the sensor
long int pardata, pardata_low, pardata_hi, real_pardata;
uint16_t illumindata = 0;
void setup () {
i2c_init(); //Initialise the I²C bus
PORTC = (1 << PORTC4) | (1 << PORTC5); //Enable pullups
Wire.begin();
accel.begin(false, 2);
Serial.begin(115200);
xbee.begin(Serial);
}
void loop () {
payload[0] = 10;
payload1[0] = 11;
**/////////////////////RF temperature sensor/////////////////////////////**
int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;
i2c_start_wait(dev + I2C_WRITE);
i2c_write(0x07);
i2c_rep_start(dev + I2C_READ);
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();
double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData = 0x0000; // Zero out the data
int frac; // Data past the decimal point
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (double)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;
float celcius = tempData - 273.15;
float fahrenheit = (celcius*1.8) + 32;
celcius *= 100;
int a = int(celcius) + 1;
payload[1] = a >> 8 & 0xff;
payload[2] = a & 0xff;
**//////////////////////////// Illumination sensor ////////////////////////////////**
sensorValue = analogRead(sensorPin);
TSR(sensorValue);
payload[3] = pardata_low >> 8 & 0xff;
payload[4] = pardata_low & 0xff;
**//////////////////////////// 3-axis accelemeter sensor ////////////////////////////////**
accel.update();
payload[5] = accel.getX()*10;
payload[6] = accel.getY()*10;
payload[7] = accel.getZ()*10;
delay(100);
**////////////////////////////// XBee send first packet///////////////////////////////////////////////**
xbee = XBee();
xbee.begin(Serial);
ZBTxRequest zbTx = ZBTxRequest(remoteAddress, payload, sizeof(payload));
zbTx.setAddress16(0xfffe);
xbee.send(zbTx);
delay(500);
**//////////////// SHT 1x temperature and humidity sensor /////////////////////////**
sht.readSR(&stat); // Read sensor status register
sht.writeSR(LOW_RES); // Set sensor to low resolution
sht.readSR(&stat); // Read sensor status register again
sht.measTemp(&rawData); // sht.meas(TEMP, &rawData, BLOCK)
sht.meas(TEMP, &rawData, NONBLOCK);
temperature = sht.calcTemp(rawData);
sht.measHumi(&rawData); // sht.meas(HUMI, &rawData, BLOCK)
humidity = sht.calcHumi(rawData, temperature);
sht.meas(HUMI, &rawData, NONBLOCK);
humidity = sht.calcHumi(rawData, temperature);
temperature *= 100;
a = int(temperature) + 1;
payload1[1] = a >> 8 & 0xff;
payload1[2] = a & 0xff;
humidity *= 100;
a = int(humidity) + 1;
payload1[3] = a >> 8 & 0xff;
payload1[4] = a & 0xff;
delay(10);
sht1.readSR(&stat1);
sht1.writeSR(LOW_RES); // Set sensor to low resolution
sht1.readSR(&stat1);
sht1.measTemp(&rawData1); // sht.meas(TEMP, &rawData, BLOCK)
temperature1 = sht1.calcTemp(rawData1);
sht1.measHumi(&rawData1); // sht.meas(HUMI, &rawData, BLOCK)
humidity1 = sht1.calcHumi(rawData1, temperature1);
delay(10);
temperature1 *= 100;
a = int(temperature1) + 1;
payload1[5] = a >> 8 & 0xff;
payload1[6] = a & 0xff;
humidity1 *= 100;
a = int(humidity1) + 1;
payload1[7] = a >> 8 & 0xff;
payload1[8] = a & 0xff;
**////////////////////////////// XBee send second packet ///////////////////////////////////////////////**
xbee = XBee();
xbee.begin(Serial);
zbTx = ZBTxRequest(remoteAddress,payload1, sizeof(payload1));
zbTx.setAddress16(0xfffe);
xbee.send(zbTx);
delay(500);
}
void TSR(int sensorValue)
{
illumindata = (sensorValue * 4 * 5) / 1.5;
pardata = 6250/6144*illumindata*10;
if(pardata > 0)
{
if(pardata < 11500)
{
real_pardata = 0.0000000020561*pardata*pardata*pardata -
0.00002255*pardata*pardata +
0.25788*pardata -
6.481;
if (real_pardata < 0)
{
real_pardata = 0;
}
pardata_hi = real_pardata/65535;
pardata_low = real_pardata%65535;
}
else
{
real_pardata = 0.0000049204*pardata*pardata*pardata -
0.17114*pardata*pardata +
1978.7*pardata -
7596900;
if (real_pardata < 0)
{
real_pardata = 0;
}
pardata_hi = real_pardata/65535;
pardata_low = real_pardata%65535;
}
}
else
{
pardata_hi = 0;
pardata_low = 0;
}
}
as I am writing this I have solved the same problem you have, though with similar hardware setup. I have used bare avr atxmega128a3u (so no arduino board) and an Xbee S1 communicating on baud rate 115200. After a few days trying to figure this out I came to conclusion, that if your avr is not running at precise clock (external xtal) and you use slightly "faster" baud rate ( >= 115200 ) Xbee's serial hardware has probably trouble recovering clock signal resulting in errors in transmission. (Maybe Xbee has slow bit sampling rate).
Anyway, by ensuring your microprocessor is running at stable clock (you should be safe here 'cause arduino has an external xtal) and by using slower baud rate (try 57600, 19200 or 9600) should solve your problem. I hope so. :) ...And don't forget to reconfigure Xbee's baud rate in XCTU.
And also it might help if you initliaze xbee only once.Move these lines into setup() function:
setup(){
// This is changed
Serial.begin(9600);
// This is new
xbee = XBee();
xbee.begin(Serial);
// ...
}
EDIT: Also you might be interested in this website where you can see what is the % of error for given clock frequency and baud rate (as well as direct register values to set if you were using bare avr) http://www.wormfood.net/avrbaudcalc.php?postbitrate=9600&postclock=16&hidetables=1