I am working with the raspberry pi and atmega 32 to use and learn SPI. it should follow a transition diagram but somewhere in the atmega it goes wrong, I don't know where it is going wrong.
this is the raspberry code
#include <wiringPi.h>
#include <stdio.h>
#include <wiringPiSPI.h>
#define SELECTADC 6
#define READY 8
#define GIVEADC 32
#define NOTREADY 0x10
#define DUMMY 0x55
#define ACK 10
#define IDLE 1
#define POLL 2
#define ADCSTART 3
#define ADCSTATE 4
#define ADCRESULT 5
main() {
int tellerPoll=0;
int teller=0;
int adcStatusTeller=0;
int status=0;
unsigned char data[4];
wiringPiSetup();
int kanaal = 0;
int adc;
int adcHigh=0;
int error=0;
if( wiringPiSPISetup (0, 500000)==-1)
{
printf("Could not initialise SPI\n");
status=0;
return;
} else {
status = IDLE;
printf("succesful initialised\n");
}
for(;;)
{
delay(20);
//wiringPiSPIDataRW(0,data,1);
switch(status){
case 0 :
exit(0);
case IDLE :
teller +=1;
if((teller % 2 == 1)&&1){
data[0] = POLL;
wiringPiSPIDataRW(0,data,1);
status = POLL;
//teller=0;
printf("Poll\n");
}
else if ((teller % 2 == 0)&&1){
status = ADCSTART;
}
break;
case POLL :
data[0] = DUMMY;
wiringPiSPIDataRW(0,data,1);
printf("Poll result: %x\n", data[0]);
if(data[0]==ACK){
status=IDLE;
printf("Poll succesfull\n");
tellerPoll=0;
}
else{
tellerPoll+=1;
if(tellerPoll>20){
status=0;
printf("No device found\n");
tellerPoll=0;
}
}
break;
case ADCSTART :
data[0]=ADCSTART;
wiringPiSPIDataRW(0,data,1);
status = ADCSTATE;
printf("ADCSTART\n");
break;
case ADCSTATE :
// printf("ADCSTATE\n");
data[0]=ADCSTATE;
wiringPiSPIDataRW(0,data,1);
//printf("%x\n",data[0]);
if(data[0]==READY){
status=ADCRESULT;
printf("Ready\n");
break;
}
else if(data[0]==NOTREADY){
printf("NOTREADY\n");
status=ADCSTATE;
adcStatusTeller+=1;
if(adcStatusTeller==100){
status=IDLE;
adcStatusTeller=0;
printf("no ADC result\n");
}
}
else{
adcStatusTeller+=1;
status =ADCSTATE;
printf("Weird result: %x\n", data[0]);
if (adcStatusTeller==100){
status=IDLE;
adcStatusTeller=0;
printf("no Results: %x \n", data[0]);
}
}
break;
case ADCRESULT :
data[0]=GIVEADC;
wiringPiSPIDataRW(0,data,1);
data[0]=DUMMY;
wiringPiSPIDataRW(0,data,1);
adc = data[0];
delay(10);
data[0]=DUMMY;
wiringPiSPIDataRW(0,data,1);
adcHigh=data[0];
//adcHigh &= 0b11000000;
//adcHigh <<=2;
//adc += adcHigh;
printf("ADC %d heeft waarde %x %x \n",kanaal, adcHigh, adc);
status=IDLE;
break;
case SELECTADC :
data[0]=SELECTADC;
wiringPiSPIDataRW(0,data,1);
data[0]=DUMMY;
wiringPiSPIDataRW(0,data,1);
if(data[0]==ACK){
delay(10);
data[0]=kanaal;
wiringPiSPIDataRW(0,data,1);
printf("ADC %s is succesfully selected",kanaal);
status=POLL;
}
else{
printf("There was an error selecting the ADC");
status=SELECTADC;
error+=1;
if(error==20){
status=POLL;
error=0;
printf("No ADC selected");
break;
}
}
break;
default :
printf("default\n");
break;
}
kanaal=0;
}
}
And Atmega32
#include <stdlib.h>
#include <avr/io.h>
void adc_init(void);
void SPI_SlaveInit(void);
unsigned char SPI_SlaveReceive(unsigned char);
void leesADC(char);
#define IDLE 1
#define POLL 2
#define ADCSTART 3
#define ADCSTATE 4
#define SELECTADC 6
#define READY 8
#define ACK 10
#define GIVEADC 32
#define NOTREADY 0x10
#define DUMMY 0x55
void SPI_SlaveInit(void)
{
/* Set MISO output, all others input */
DDRB = (1<<PB6);
/* Enable SPI */
SPCR = (1<<SPE);
}
unsigned char SPI_SlaveReceive(unsigned char data)
{
SPDR = data;
/* Wait for reception complete */
while(!(SPSR & (1<<SPIF) ));
/* Return data register */
return SPDR;
}
//starADC
void leesADC(char kanaal)
{
ADMUX &= 0b11100000;
ADMUX |= kanaal & 7;
ADCSRA |= (1<<ADSC);
}
void adc_init(void)
{
ADMUX=(1<<REFS0)|(1<<ADLAR); //voedings U als referentie, links uitlijnen in de 10bit
ADCSRA=(1<<ADEN); // adc enablen, start conversion, auto trigger enable
}
int main(void)
{
DDRC= 0b11111111;
DDRD= 0b11111111;
SPI_SlaveInit();
adc_init();
int kanaal=0;
leesADC(kanaal);
char stap;
char status;
while(1)
{
switch(stap){
case IDLE :
stap = SPI_SlaveReceive(status);
break;
case POLL :
status = ACK;
stap=IDLE;
PORTD=15;
break;
case ADCSTART :
status = ADCSTART;
leesADC(kanaal);
PORTD=255;
break;
case ADCSTATE :
if ((ADCSRA & (1<<ADIF)) == 0){
status = NOTREADY;
} else{
status = READY;
}
stap=IDLE;
break;
case GIVEADC :
stap= ADCH;
break;
case SELECTADC :
kanaal = SPI_SlaveReceive(DUMMY);
stap=DUMMY;
break;
default : ;
}
}
}
Thanks in advance.
You don't initialize the stap variable, which means its value will be indeterminate. Attempting to use it in the switch statement will lead to undefined behavior.
I suppose you should be initializing it to IDLE:
int stap = IDLE;
Related
I am trying to design a GPS car tracker with a SIM808 module using a STM32F103RET6 header board and I want to get the location link messaged to my phone by sending an SMS to the module. Right now my code works but only when I reset the board after sending each SMS. I attached my code can you figure out what is the problem?
main code :
#include <stm32f10x.h>
#include "usart.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
char S=0x1A;
#define Enter usart_sendchar('\n');
#define CR usart_sendchar('\r');
#define GIM usart_sendchar('"');
#define SUB usart_sendchar(S);
#include "stm32f10x.h"
#include <string.h>
char get_Enter = 0;
uint8_t ch;
char str1[300];
char str2[100];
int i=0;
char flag=0;
char str_tmp[20];
char str_tmp2[20];
char* p;
volatile uint32_t msTicks;
//calling all the functions
void Send_SMS(char *text);
void CMTI(void);
void wait_to_get(char ch);
void del_All_SMS(void);
void CMGF_1(void);
void Delay (uint32_t Time);
void CMGR (void);
void CGNSPWR_1(void);
void CGNSINF(void);
void interrupt_activation(void);
void CGNSINF_C(void);
void AT(void);
void Delay (uint32_t dlyTicks);
void SysTick_Handler(void);
// the interrupt handler for the systick module
void SysTick_Handler(void) {
msTicks++;
}
void Delay (uint32_t dlyTicks) {
uint32_t curTicks;
curTicks = msTicks;
while ((msTicks - curTicks)< dlyTicks);
}
void Send_SMS(char *text)
{
CMGF_1();
Delay(500);
str_tmp[0]='\0';
Delay(100);
strcpy(str_tmp,"AT+CMGS=");
Delay(500);
usart_sendstring(str_tmp);
GIM
str_tmp[0]='\0';
Delay(100);
strcpy(str_tmp,"+98905xxxxxxx");
Delay(500);
usart_sendstring(str_tmp);
GIM
Enter
CR
Delay(500);
usart_sendstring(text);
Enter
CR
str_tmp[0]='\0';
Delay(500);
SUB
Delay(100);
del_All_SMS();
}
void USART1_IRQHandler(void) {
ch = USART1->DR & 0xFF;
if (ch == '\n'){ // 13 enter
get_Enter =1;
}
else{
str1[i]= ch;
i++;
}
}
void CMGF_1(void)
{
str_tmp[0]='\0';
Delay(100);
strcpy(str_tmp,"AT+CMGF=1");
Delay(500);
usart_sendstring(str_tmp);
Enter
CR
}
void del_All_SMS(void)
{
str_tmp[0]='\0';
Delay(100);
strcpy(str_tmp,"AT+CMGD=1,4");
Delay(500);
usart_sendstring(str_tmp);
Enter
CR
}
void CMGR(void)
{
str_tmp[0]='\0';
Delay(100);
strcpy(str_tmp,"AT+CMGR=1");
Delay(500);
usart_sendstring(str_tmp);
Enter
CR
}
void CGNSINF(void)
{
str_tmp[0]='\0';
Delay(100);
strcpy(str_tmp,"AT+CGNSINF");
Delay(500);
usart_sendstring(str_tmp);
Enter
CR
}
void CGNSPWR_1(void)
{
str_tmp[0]='\0';
Delay(100);
strcpy(str_tmp,"AT+CGNSPWR=1");
Delay(500);
usart_sendstring(str_tmp);
Enter
CR
}
void AT(void)
{
str_tmp[0]='\0';
Delay(100);
strcpy(str_tmp,"AT");
Delay(500);
usart_sendstring(str_tmp);
Enter
CR
}
int main()
{
SystemInit();
SysTick_Config(SystemCoreClock/1000); // setup systick timer for 1ms interrupts
usart_init();
AT();
p=NULL;
check:AT();
Delay(2000);
p=strstr(str1,"OK");
if(p==NULL) goto check;
CMGF_1();
Delay(500);
CGNSPWR_1();
Delay(500);
del_All_SMS();
Delay(500);
RCC->APB2ENR |= (1<<3);
GPIOB->CRL &= ~0xF;
GPIOB->CRL |= 0x3;
while (1)
{
if (get_Enter ==1)
{
if (flag==0){
////waiting for +CMTI: from sim800
do
{
p=strstr(str1,"+CMTI:");
}
while(p==NULL);
Delay(1000);
// sending AT+CMGR=1 command
if (p!=NULL)
{
CMGR();
Delay(350);
flag=1;
}
}
if (flag==1) {
p=strstr(str1,"+CMGR");
if (p){
p=strstr(str1,"loc");
if (p!=NULL)
{
CGNSINF();
Delay(300);
}
else if (p==NULL)
{
del_All_SMS();
memset(str1, 0, 300);
flag=0;
}
p=strstr(str1,"+CGNSINF:");
if (p)
{
float a[5];
char str2[80];
const char s[2] = ",";
char *token;
// getting the lattitude and longitude
token = strtok(p, s);
for (int i=0;i<5;i++){
sprintf( str2," %s\n", token );
a[i]=atof(str2);
token = strtok(NULL, s);
}
sprintf(str2,"https://maps.google.com/?q=%.6f,%.6f",a[3],a[4]);
Send_SMS(str2);
p=NULL;
del_All_SMS();
flag=0;
memset(str1, 0, 300);
}
}
}
}
}
}
usart code :
#include "stm32f10x.h"
#include "usart.h"
char str[200];
char data;
//// initialize usart
void usart_init(void)
{
RCC->APB2ENR |= ( 1UL << 0); /* enable clock Alternate Function */
AFIO->MAPR &= ~( 1UL << 2); /* clear USART1 remap */
RCC->APB2ENR |= ( 1UL << 2); /* enable GPIOA clock */
GPIOA->CRH &= ~(0xFFUL << 4); /* clear PA9, PA10 */
GPIOA->CRH |= (0x0BUL << 4); /* USART1 Tx (PA9) output push-pull */
GPIOA->CRH |= (0x04UL << 8); /* USART1 Rx (PA10) input floating */
RCC->APB2ENR |= ( 1UL << 14); /* enable USART#1 clock */
USART1->BRR=0x1D4C; // 9600 #72MHz
// USART1->BRR = 0x0271; /* 115200 baud # PCLK2 72MHz */
USART1->CR1 = (( 1UL << 2) | /* enable RX */
( 1UL << 3) | /* enable TX */
( 0UL << 12) ); /* 1 start bit, 8 data bits */
USART1->CR2 = 0x0000; /* 1 stop bit */
USART1->CR3 = 0x0000; /* no flow control */
USART1->CR1 |= ( 1 << 13); /* enable USART */
USART1->CR1 |= ( 1UL << 5); // RXNE interrupt enable
NVIC_SetPriority(USART1_IRQn,5); /* Default priority group 0, can be 0(highest) - 31(lowest) */
NVIC_EnableIRQ(USART1_IRQn); /* Enable UART0 Interrupt */
}
void usart_sendchar(char data){
while(!(USART1->SR&(1<<7)));
USART1->DR=data;
}
char usart_getchar(void)
{
while (!(USART1->SR&(1<<5)));
data=USART1->DR ;
return data;
}
void usart_getstring(char *str)
{
char *temp = str;
do{
*temp = usart_getchar();
usart_sendchar (*temp) ;
} while(*(temp++) != 0x0D );
*(temp-1) = 0;
}
void usart_sendstring(char *s)
{
while (*s)
{
usart_sendchar(*s);
s++;
}
}
I have problem when want to determine the address for each LED in dot-matrix 8x8 74HC595, im trying to light on only 1 LED specifically with the address. i have tried many tutorial and documentation but still no luck to light on only 1 LED with spesific location.
this is my circuit design :
https://www.sunfounder.com/learn/Super_Kit_V2_for_RaspberryPi/lesson-12-driving-dot-matrix-by-74hc595-super-kit-for-raspberrypi.html
my code with C:
#include <wiringPi.h>
#include <stdio.h>
#define SDI 0 //serial data input
#define RCLK 1 //memory clock input
#define SRCLK 2 //shift register clock input
unsigned char LED[8] ={0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
void pulse(int pin)
{
digitalWrite(pin, 0);
digitalWrite(pin, 1);
}
void ShiftOUT(unsigned char byte)
{
int i;
for(i=0;i<8;i++)
{
// char a = byte & (0x80 >> i)) > 0;
digitalWrite(SDI, (( byte & (0x80 >> i)) > 0));
printf("%d", (( byte >> i > 0)));
pulse(SRCLK);
}
printf("\n","==================");
}
void init(void)
{
pinMode(SDI, OUTPUT);
pinMode(RCLK, OUTPUT);
pinMode(SRCLK, OUTPUT);
digitalWrite(SDI, 0);
digitalWrite(RCLK, 0);
digitalWrite(SRCLK, 0);
}
int main(void)
{
int i;
if(wiringPiSetup() == -1)
{
printf("setup wiringPi failed !");
return 1;
}
init();
while(1)
{
for(i=0;i<8;i++)
{
ShiftOUT(LED[i]);
pulse(RCLK);
// printf("=======pull latch========");
// printf("\n");
delay(150);
}
delay(500);
}
return 0;
}
This code i tried will light on 1 row,i want to light on 1 LED with spesific location
Here is the link i use for simulation to addressing the LED : https://www.riyas.org/2013/12/online-led-matrix-font-generator-with.html
Any help?Thank you
The functions cfsetospeed and cfsetispeed take baud rate as type speed_t:
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
The type speed_t is basically an integer, but casting is not a solution, as can be seen from the baudrate definitions in termios.h:
#define B0 0x00000000
#define B50 0x00000001
#define B75 0x00000002
// ...
#define B9600 0x0000000d
#define B19200 0x0000000e
#define B38400 0x0000000f
When I process user input (e.g. from file), I convert a string such as "9600" to integer 9600, and then to B9600. I'm basically looking for a generic way to convert the following:
// 0 -> B0
// 50 -> B50
// 75 -> B75
// ...
// 9600 -> B9600
// 19200 -> B19200
// 38400 -> B38400
One way to convert from int (such as 9600) to speed_t (such as B9600) is a switch-case structure. Is there a better way to achieve this?
I came across needing this. Pasting the switch case statement here for you to copy.
int get_baud(int baud)
{
switch (baud) {
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 230400:
return B230400;
case 460800:
return B460800;
case 500000:
return B500000;
case 576000:
return B576000;
case 921600:
return B921600;
case 1000000:
return B1000000;
case 1152000:
return B1152000;
case 1500000:
return B1500000;
case 2000000:
return B2000000;
case 2500000:
return B2500000;
case 3000000:
return B3000000;
case 3500000:
return B3500000;
case 4000000:
return B4000000;
default:
return -1;
}
}
You need a lookup table, but not a naive one:
#include <stdio.h>
#include <termios.h>
struct
{
int rawrate;
int termiosrate;
} conversiontable[] =
{
{0, B0},
{50, B50},
{75, B75},
// you need to complete the table with B110 to B38400
};
int convertbaudrate(int rawrate)
{
for (int i = 0; i < sizeof(conversiontable) / sizeof(conversiontable[0]); i++)
{
if (conversiontable[i].rawrate == rawrate)
{
return conversiontable[i].termiosrate;
}
}
return -1; // invalid baud rate
}
int main()
{
printf("%d -> %d\n", 50, convertbaudrate(50));
printf("%d -> %d\n", 75, convertbaudrate(75));
}
That should autoexplain. If not, please comment.
My brother and I have been trying to get this working for days now and we just can't figure out what we are doing wrong, we could really use some help please!
What we're trying to accomplish is reading in data from a light sensor on an RPI expansion board through our own program written in C, using the BCM2835 library.
This is the light sensor we are using: TSL2561
https://cdn-shop.adafruit.com/datasheets/TSL2561.pdf
We are using a raspberry pi B+ model with Raspbian installed on it (through noobs).
This is the C library we are using:
http://www.airspayce.com/mikem/bcm2835/
I activated I2c through the raspian configuration.
and I detected the light sensor through i2ctools and it shows up correctly with adress 0x29.
We get 0 values back with our reads, and we tested our commands with an osciloscope and it seems he does ACK the write commands. he just doesn't send anything back...
Can someone please help us ?
#include <bcm2835.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
uint16_t clk_div = BCM2835_I2C_CLOCK_DIVIDER_148;
uint8_t slave_address = 0x29; //0101001 - this is the sensor address
uint64_t delay = 70000;
int main(int argc, char **argv)
{
/*
DATA0LOW Ch 7:0 ADC channel 0 lower byte
DATA0HIGH Dh 7:0 ADC channel 0 upper byte
*/
char buffer[10]={0};
char addr;
uint16_t data;
uint8_t data2;
int i =0;
char writeBuff[1] = {0x8C}; ////Address the Ch0 lower data register
char readBuff[10];
char writeBuff2[2] = {0x8D}; ////Address the Ch0 upper data register
char readBuff2[10];
char *wb_ptr,*r_ptr,*wb_ptr2,*r_ptr2;
wb_ptr = writeBuff;
wb_ptr2 = writeBuff2;
r_ptr = readBuff;
r_ptr2 = readBuff2;
printf("Running ... \n");
bcm2835_init():
bcm2835_i2c_begin();
bcm2835_i2c_setSlaveAddress(slave_address); //0x29
printf("Clock divider set to: %d\n", clk_div);
printf("Slave address set to: %d or %X\n",slave_address,slave_address);
//needed according to datasheet to read although unsure if it needs to be sent in two writes or in one ? 0x83 instead of 0x80 + 0x03 ?
bcm2835_i2c_write(0x80, 1); //command register
bcm2835_i2c_write(0x03, 1); //command itself
bcm2835_delayMicroseconds(delay);
//--------------------------
while (1)
{
printf("reading data from light sensor\n");
bcm2835_i2c_write(wb_ptr, 1); // 0x8C
bcm2835_delayMicroseconds(delay);
data = bcm2835_i2c_read(readBuff,1);
bcm2835_delayMicroseconds(delay);
printf("Read Result 1 = %d\n", data);
bcm2835_i2c_write(wb_ptr2, 1); //0x8D
bcm2835_delayMicroseconds(delay);
data2 = bcm2835_i2c_read(readBuff2,1);
bcm2835_delayMicroseconds(delay);
printf("Read Result 2 = %d\n", data);
bcm2835_delay(1000);
}
bcm2835_i2c_end();
bcm2835_close();
printf("... done\n");
return 0;
}
This is a Quick edit
#include <bcm2835.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
uint16_t clk_div = BCM2835_I2C_CLOCK_DIVIDER_148;
uint8_t slave_address = 0x29; //0101001 - this is the sensor address
uint64_t delay = 70000;
int main(int argc, char **argv)
{
/*
DATA0LOW Ch 7:0 ADC channel 0 lower byte
DATA0HIGH Dh 7:0 ADC channel 0 upper byte
*/
/*
enum bcm2835I2CReasonCodes { BCM2835_I2C_REASON_OK = 0x00, BCM2835_I2C_REASON_ERROR_NACK = 0x01, BCM2835_I2C_REASON_ERROR_CLKT = 0x02, BCM2835_I2C_REASON_ERROR_DATA = 0x04 }
*/
char buffer[10]={0};
char addr;
uint16_t data;
uint8_t data2;
uint8_t error = 0xff;
int i =0;
char writeBuff[1] = {0x8C}; ////Address the Ch0 lower data register
char readBuff[10];
char writeBuff2[2] = {0x8D}; ////Address the Ch0 upper data register
char readBuff2[10];
char writeBuff3[2] = {0x80};
char writeBuff4[2] = {0x03};
char *wb_ptr,*r_ptr,*wb_ptr2,*r_ptr2,*r_ptr3,*r_ptr4;
wb_ptr = writeBuff;
wb_ptr2 = writeBuff2;
r_ptr = readBuff;
r_ptr2 = readBuff2;
r_ptr3 = writeBuff3;
r_ptr4 = writeBuff4;
printf("Running ... \n");
bcm2835_init();
bcm2835_i2c_begin();
bcm2835_i2c_setSlaveAddress(slave_address); //0x29
printf("Clock divider set to: %d\n", clk_div);
printf("Slave address set to: %d or %X\n",slave_address,slave_address);
//needed according to datasheet to read although unsure if it needs to be sent in two writes or in one ? 0x83 instead of 0x80 + 0x03 ?
bcm2835_i2c_write(r_ptr3, sizeof(r_ptr3)); //command register
bcm2835_i2c_write(r_ptr4, sizeof(r_ptr4)); //command itself
bcm2835_delayMicroseconds(delay);
//--------------------------
// Blink
while (1)
{
printf("reading data from light sensor\n");
error = bcm2835_i2c_write(wb_ptr, sizeof(wb_ptr)); // 0x8C
bcm2835_delayMicroseconds(delay);
data = bcm2835_i2c_read(readBuff,sizeof(readBuff));
bcm2835_delayMicroseconds(delay);
printf("readbuff1 = 0x%02X \n",readBuff);
printf("error result = 0x%02X\n", error);
printf("Read Result 1 = 0x%02X\n", data);
error = bcm2835_i2c_write(wb_ptr2, sizeof(wb_ptr2)); //0x8D
bcm2835_delayMicroseconds(delay);
data2 = bcm2835_i2c_read(readBuff2,sizeof(readBuff2));
bcm2835_delayMicroseconds(delay);
printf("readbuff2 = 0x%02X \n",readBuff2);
printf("error result = 0x%02X\n", error);
printf("Read Result 2 = 0x%02X\n", data2);
bcm2835_delay(1000);
}
bcm2835_i2c_end();
bcm2835_close();
printf("... done\n");
return 0;
}
I managed to fix it, I had several problems , one of which was that I was adressing the wrong adress to send commands, it has to be 0xa0 instead of 0x80.
#include <bcm2835.h>
#include <stdio.h>
int main(void)
{
/*
DATA0LOW Ch 7:0 ADC channel 0 lower byte
DATA0HIGH Dh 7:0 ADC channel 0 upper byte
*/
/*
enum bcm2835I2CReasonCodes { BCM2835_I2C_REASON_OK = 0x00, BCM2835_I2C_REASON_ERROR_NACK = 0x01, BCM2835_I2C_REASON_ERROR_CLKT = 0x02, BCM2835_I2C_REASON_ERROR_DATA = 0x04 }
*/
if (!bcm2835_init())
return 1;
char uitgelezenTempWaarde[1];
int totalTemp[2];
int error =0;
bcm2835_i2c_begin(); // start i2c
bcm2835_i2c_setSlaveAddress(0x29); // slave address
bcm2835_i2c_set_baudrate(1000); // default
//----------- turn channels on for measurement ------
uitgelezenTempWaarde[0] = 0xa0;
error = bcm2835_i2c_write(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
uitgelezenTempWaarde[0] = 0x03;
error = bcm2835_i2c_write(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
bcm2835_delay(500);
error = bcm2835_i2c_read(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
//----------- read data ------
uitgelezenTempWaarde[0] = 0xac; //DATA0LOW Ch 7:0 ADC channel 0 lower byte
error = bcm2835_i2c_write(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
error = bcm2835_i2c_read(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
totalTemp[1]= (int)uitgelezenTempWaarde[0];
uitgelezenTempWaarde[0] = 0xad; //DATA0HIGH Dh 7:0 ADC channel 0 upper byte
error = bcm2835_i2c_write(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
error = bcm2835_i2c_read(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
totalTemp[0] = (int)uitgelezenTempWaarde[0]; //
totalTemp[0] *= 256; //hex conversion for the highest byte so it is seen as a high number (16 bits)
printf("The light value is :%d\n",totalTemp[0]+totalTemp[1]);
bcm2835_i2c_end();
bcm2835_close();
return 0;
}
I'm working on a personal home automation project.
On the server side, I have an Arduino Pro Mini with:
a 433 MHz TX module on pin 2
a 433 MHz RX module on pin 3
a DHT22 probe on pin 4 (with 10k pull-up)
a DHT22 probe on pin 5 (with 10k pull-up)
I have two absolutely identical of these modules; one will be the radio relay (and DHT "server") and the other a secondary DHT "server".
When it is linked to my laptop (Debian Wheezy) through an FTDI cable, it can read both local probes and switch my wall plugs on/off thanks to a C program I wrote. I'd like to use it from a Raspberry Pi. But on the Raspberry Pi (with the same FTDI cable on USB), it executes the first command I send and then hangs my terminal, forcing me to use CTRL+C.
Here is the sketch on the Arduino side (header) :
/**
* probe.h
*
* #author David Mézière <...>
*/
/**
* DHT probe result
*
*/
struct Probe {
float temperature;
float humidity;
};
Main file :
/**
* probe.ino
*
* #author David Mézière <...>
*/
#include "probe.h"
/**
* Uses DHT sensor library, from Adafruit.
* #see https://github.com/adafruit/DHT-sensor-library
*/
#include <DHT.h>
/**
* Uses RC Switch library, from sui77.
* #see https://github.com/sui77/rc-switch
*/
#include <RCSwitch.h>
// Pinout definitions
#define TX 2 // 433 MHz transmitter pin number
#define RX 3 // 433 MHz receiver pin number
#define PROBE1 4 // First DHT22 probe pin number
#define PROBE2 5 // Second DHT22 probe pin number
#define LED 13 // On-board status LED pin number
RCSwitch radio = RCSwitch();
// DHT probes definition
DHT dht1(PROBE1, DHT22);
DHT dht2(PROBE2, DHT22);
// Incomming command buffer
byte cmd[9];
/**
* Setup
*
* #return void
*/
void setup()
{
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
Serial.begin(9600);
Serial.setTimeout(1000); // doesn't fix the problem
// Attach receiver to interrupt 1, meaning pin 3
radio.enableReceive(1);
radio.enableTransmit(TX);
dht1.begin();
dht2.begin();
// Debug: Internal LED will blink 3 times rapidly to show when a reboot occurs.
for (int i = 0; i < 3; i++) {
digitalWrite(LED, HIGH);
delay(250);
digitalWrite(LED, LOW);
delay(250);
}
}
/**
* Loop
*
* #return void
*/
void loop()
{
if (Serial.available() == 9 && readCommand()) {
// Lights-up internal LED to show when a command has been executed
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
}
}
/**
* Query probe
*
* Query provided [dht] probe until [retry] times for both temperature and humidity.
*
* #param DHT dht Pointer to DHT object
* #param int retry Number of tries
* #return Probe Probe result (float temperature in °C, float humidity in %)
*/
Probe queryProbe(DHT* dht, int retry)
{
Probe probe;
// Query DHT22 probe for temperature, a maximum of [retry] times.
for (int t = 0; t < retry; t++) {
probe.temperature = dht->readTemperature(false);
if (!isnan(probe.temperature)) {
break;
}
delay(50);
}
// Query DHT22 probe for humidity, a maximum of [retry] times.
for (int h = 0; h < retry; h++) {
probe.humidity = dht->readHumidity();
if (!isnan(probe.humidity)) {
break;
}
delay(50);
}
return probe;
}
/**
* Read command
*
* If serial buffer contains 2 bytes, move them to a local buffer and return true. else return false.
*
* #return boolean
*/
boolean readCommand()
{
// Reads the current buffer
Serial.readBytes(cmd, 9);
// Calculates the check sum of payload
int sum = cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5] ^ cmd[6] ^ cmd[7];
// Checking header and checksum a header of 0xBA 0xB1 means DHT query
if (cmd[0] == 0xBA && cmd[1] == 0xB1 && cmd[8] == sum) {
unsigned int module = cmd[2];
unsigned int probe = (cmd[4] << 24) + (cmd[5] << 16) + (cmd[6] << 8) + cmd[7];
Probe result;
switch (module) {
case 1:
// Selects the right probe
if (probe == 1) {
result = queryProbe(&dht1, 3);
} else if (probe == 2) {
result = queryProbe(&dht2, 3);
}
// Send status repport to client
Serial.print("1;");
Serial.print(module);
Serial.print(";");
Serial.print(probe);
Serial.print(";");
Serial.print(result.temperature);
Serial.print(";");
Serial.println(result.humidity);
Serial.flush(); // Doesn't fix the problem
break;
}
return true;
// A header of 0xBA 0xB2 means rf wall plugs query
} else if (cmd[0] == 0xBA && cmd[1] == 0xB2 && cmd[8] == sum) {
unsigned int proto = cmd[2];
unsigned int length = cmd[3];
unsigned int value = (cmd[4] << 24) + (cmd[5] << 16) + (cmd[6] << 8) + cmd[7];
radio.send(value, length);
// Send status repport to client
Serial.print("2;");
Serial.print(proto);
Serial.print(";");
Serial.print(length);
Serial.print(";");
Serial.print(value);
Serial.print(";");
Serial.println("OK");
Serial.flush(); // Doesn't fix the problem
return true;
} else {
Serial.println("KO");
Serial.flush(); // Doesn't fix the problem
return false;
}
}
And on the client side :
/**
* probe.c
*
* #author David Mézière <...>
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <getopt.h>
const char* device;
static int module = 0; // uint_8 ?
static int probe = 0; // uint_8 ?
const char* proto;
static int length = 0; // uint_8 ?
static int value = 0; // uint_32 ?
static int verbose = 0; // uint_8 ?
void help()
{
printf("usage:\n");
printf("\n");
printf("probe [options] [arguments]\n");
printf("\n");
printf("options:\n");
printf(" -h|--help: Displays this help and exit\n");
printf(" -v|--verbose: Be more verbose\n");
printf("\n");
printf("arguments:\n");
printf(" -d|--device: string Serial device to use (ex: /dev/ttyUSB0)\n");
printf(" -m|--module: integer DHT22 module to query\n");
printf(" -p|--probe: integer DHT22 probe to query\n");
printf(" -r|--proto: string Radio / IR protocol\n");
printf(" -l|--length: integer Radio / IR value length in bits\n");
printf(" -a|--value: integer Radio / IR value\n");
printf("\n");
printf("examples:\n");
printf(" probe --device /dev/ttyUSB0 --module 1 --probe 1 : Will query first DHT22 probe of first module\n");
printf(" probe --proto radio1 --length 12 --value 5393 : Will send value 5393 on 12 bits over the air using protocol 1\n");
printf(" probe --proto ir11 --length 64 --value 3772793023 : Will send value 3772793023 on 64 bits by infra red using protocol 11\n");
}
void parseArgs(int argc, char **argv)
{
int c;
while (1) {
static struct option long_options[] = {
{"device", required_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{"module", required_argument, 0, 'm'},
{"probe", required_argument, 0, 'p'},
{"proto", required_argument, 0, 'r'},
{"length", required_argument, 0, 'l'},
{"value", required_argument, 0, 'a'},
{"verbose", no_argument, 0, 'v'},
{0, 0, 0, 0}
};
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long(argc, argv, "d:hm:p:v", long_options, &option_index);
/* Detect the end of the options. */
if (c == -1) {
break;
}
switch (c) {
case 0:
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0) {
break;
}
printf("option %s", long_options[option_index].name);
if (optarg) {
printf (" with arg %s", optarg);
}
printf("\n");
break;
case 'd':
device = optarg;
break;
case 'h':
help();
exit(0);
break;
case 'm':
module = atoi(optarg);
break;
case 'p':
probe = atoi(optarg);
break;
case 'r':
proto = optarg;
break;
case 'l':
length = atoi(optarg);
break;
case 'a':
value = atoi(optarg);
break;
case 'v':
verbose = 1;
break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
abort();
}
}
/* Print any remaining command line arguments (not options). */
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc) {
printf("%s ", argv[optind++]);
}
putchar('\n');
}
if (&device[0] == '\0') {
fprintf(stderr, "--device is mandatory\n");
exit(1);
} else if (verbose) {
printf("Device: %s\n", device);
}
if (verbose) {
printf("Querying probe %i of module %i.\n", probe, module);
}
}
void initSerial(int fd)
{
struct termios toptions;
/* get current serial port settings */
tcgetattr(fd, &toptions);
/* set 9600 baud both ways */
cfsetispeed(&toptions, B9600);
cfsetospeed(&toptions, B9600);
/* 8 bits, no parity, no stop bits */
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
/* Canonical mode */
toptions.c_lflag |= ICANON;
/* commit the serial port settings */
tcsetattr(fd, TCSANOW, &toptions);
}
int main(int argc, char **argv)
{
// Parses command line arguments
parseArgs(argc, argv);
int fd, n, i;
char buf[64] = "temp text";
/* open serial port */
fd = open(device, O_RDWR | O_NOCTTY);
if (verbose) {
printf("Device %s opened as %i\n", device, fd);
}
/*
* Note: Most Arduinos models will reboot upon connection, and they need
* some time for it. I use a pro/mini that doesn't, so i commented it out.
*/
// usleep(3500000);
// Sets the serial port settings (9600 bps, 8 bits, no parity, no stop bits)
initSerial(fd);
/**
* 72 bits
* | Header | Param 1 | Param 2 | Param 3 | sum |
* | 16 b | 8 b | 8 b | 32 b | 8 b |
* Cas 1 : Requête DHT | 0xba 0xb1 | module | 0x00 | sonde | sum |
* Cas 2 : Requête radio | 0xba 0xb2 | proto | length | value | sum |
* Cas 3 : Requête IR | 0xba 0xb3 | proto | length | value | sum |
*/
unsigned char oBuf[9];
// printf("%s\n", proto);
// printf("%i\n", length);
if (module > 0 && probe > 0) {
if (verbose) {
printf("DHT mode\n");
}
oBuf[0] = 0xBA;
oBuf[1] = 0xB1; // DHT query
oBuf[2] = module;
oBuf[3] = 0x00;
oBuf[4] = (probe >> 24) & 0xFF;
oBuf[5] = (probe >> 16) & 0xFF;
oBuf[6] = (probe >> 8) & 0xFF;
oBuf[7] = probe & 0xFF;
oBuf[8] = oBuf[2];
oBuf[9] = '\n';
// Calculates the XOR sum
for (i = 3; i < 8; i++) {
oBuf[8] ^= oBuf[i];
}
// sprintf(oBuff, "%c%c%c%c%c%c", 0xba, 0xb1, module, 0x00, probe, sum);
} else if (strcmp((const char*)proto, "radio1") == 0 && length > 0) {
if (verbose) {
printf("Radio mode\n");
}
oBuf[0] = 0xBA;
oBuf[1] = 0xB2; // Radio query
oBuf[2] = 0x01; // Protocol 1
oBuf[3] = length;
oBuf[4] = (value >> 24) & 0xFF;
oBuf[5] = (value >> 16) & 0xFF;
oBuf[6] = (value >> 8) & 0xFF;
oBuf[7] = value & 0xFF;
oBuf[8] = oBuf[2];
oBuf[9] = '\n';
// Calculates the XOR sum
for (i = 3; i < 8; i++) {
oBuf[8] ^= oBuf[i];
}
} else {
if (verbose) {
printf("Unknown mode\n");
}
}
/* Send the buffer */
write(fd, oBuf, 9);
/* Receive string from Arduino */
n = read(fd, buf, 64);
/* insert terminating zero in the string */
buf[n] = 0;
if (verbose) {
printf("%i bytes read, buffer contains: %s\n", n, buf);
} else {
printf("%s", buf);
}
return 0;
}
I compile it using just gcc probe.c -o probe.
On Debian, I can use the system as much as I want, it works:
dmeziere#portable2-wlan:~/dev/probe$ gcc probe.c -o probe
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 1
1;1;1;23.60;43.10
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 2
1;1;2;23.60;38.50
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --proto radio1 --length 24 --value 5396
2;1;24;5396;OK
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --proto radio1 --length 24 --value 5393
2;1;24;5393;OK
On Raspbian, the first call works, but the second hangs my terminal and I have to do CTRL+C:
dmeziere#raspberrypi:~/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 1
1;1;1;23.90;39.00
dmeziere#raspberrypi:~/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 2
^C
I found it !
It seems like on Raspbian, the communications were terminated by a NULL character. But not on Debian. And this NULL character was polluting my calculations of incomming buffer length. So i ended up by eventually suppress it on the Arduino side :
boolean readCommand()
{
// Reads the current buffer
Serial.readBytes(cmd, 9);
// If sender sends a null character, remove it.
int test = Serial.peek();
if (test == 0x00) {
test = Serial.read();
}
// ...
}