Create Callback function for I2C light sensor using Arduino IDE - c

I am trying to create the callback function and display the parameters in the loop function without initializing a global variable.
#include <Wire.h>
#define Addr 0x39
void setup() {
Wire.begin();
Serial.begin(115200);
}
void loop()
{
tmg39931(green, red, blue, cdata, c);
delay(100);
}
void tmg39931(float green, float red, float blue, float cdata, float c){
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select Enable register
Wire.write(0x80);
// Power ON, ALS enable, Proximity enable, Wait enable
Wire.write(0x0F);
// Stop I2C transmission
Wire.endTransmission();
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select ADC integration time register
Wire.write(0x81);
// ATIME : 712ms, Max count = 65535 cycles
Wire.write(0x00);
// Stop I2C transmission
Wire.endTransmission();
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select Wait time register
Wire.write(0x83);
// WTIME : 2.78ms
Wire.write(0xFF);
// Stop I2C transmission
Wire.endTransmission();
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select control register
Wire.write(0x8F);
// AGAIN is 1x
Wire.write(0x00);
// Stop I2C transmission
Wire.endTransmission();
delay(300);
//Reading the values
unsigned int data[9];
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select data register
Wire.write(0x94);
// Stop I2C transmission
Wire.endTransmission();
// Request 9 bytes of data
Wire.requestFrom(Addr, 9);
// Read the 9 bytes of data
// cData channel LSB, cData channel MSB, Red channel LSB, Red channel MSB
// Green channel LSB, Green channel MSB, Blue channel LSB, Blue channel MSB, proximity
if(Wire.available() == 9)
{
data[0] = Wire.read();
data[1] = Wire.read();
data[2] = Wire.read();
data[3] = Wire.read();
data[4] = Wire.read();
data[5] = Wire.read();
data[6] = Wire.read();
data[7] = Wire.read();
data[8] = Wire.read();
}
// Convert the data
float cData = data[1] * 256.0 + data[0];
float red = data[3] * 256.0 + data[2];
float green = data[5] * 256.0 + data[4];
float blue = data[7] * 256.0 + data[6];
float c = data[8];
// Output data to serial monitor
// Serial.print("Green Color Luminance : ");
// Serial.println(green);
// Serial.print("Red Color Luminance : ");
// Serial.println(red) ;
// Serial.print("Blue Color Luminance : ");
// Serial.println(blue) ;
// Serial.print("InfraRed Luminance : ");
// Serial.println(cData) ;
// Serial.print("Proximity of the device : ");
// Serial.println(c);
delay(500);
}
}
I am not able to receive my values to loop function due to the wrong implementation of the function.
I need your suggestion to make this kind of solution or any different way which will be useful to make a callback function.

On Arduino it is typical to use global variables for things. You'll be having hard time trying to fight with that.
If you want to get multiple values read from your function, you could define a struct that packs those values, and pass a pointer to that struct as an output parameter, and fill it in your function.
I don't believe that Arduino has callbacks out of the box, but you might implement an event loop yourself.

Related

ESP32 LoRa settings are not applied

I use this board from Heltec automation, which has LoRa and an OLED display onboard.
I do not use the Heltec library, instead I use the lora.h library directly.
When I want to adjust the spreading factor and transmitting power, these settings are not applied and there is no change in the signal. Also I have read different registers regarding spreading factor and transmitting power before and after setting and there is no change.
In summary, when I try this, nothing happens.
LoRa.setTxPower(20);
LoRa.setSpreadingFactor(12);
The code:
#include <Arduino.h>
#include <LoRa.h>
#include <Wire.h>
#include <SSD1306Wire.h>
SSD1306Wire display(0x3c, SDA_OLED, SCL_OLED, GEOMETRY_128_64);
const int csPin = 18; // LoRa radio chip select
const int resetPin = 14; // LoRa radio reset
const int irqPin = 26; // change for your board; must be a hardware interrupt pin
String outgoing; // outgoing message
byte msgCount = 0; // count of outgoing messages
byte localAddress = 0xBB; // address of this device
byte destination = 0xFF; // destination to send to
long lastSendTime = 0; // last send time
int interval = 2000; // interval between sends
int msgLoopCounter = 0;
void setup() {
Serial.begin(115200);
while (!Serial);
// Set OLED reset pin to HIGH
pinMode(RST_OLED, OUTPUT);
digitalWrite(RST_OLED, HIGH);
delay(1000);
// Initialze OLED display
if (!display.init()) {
display.setContrast(255);
display.clear();
display.display();
while (true);
}
Serial.println("Display init succeeded.");
// Initialize LoRa
LoRa.setPins(csPin, resetPin, irqPin); // set CS, reset, IRQ pin
LoRa.setTxPower(20);
LoRa.setSpreadingFactor(12);
if (!LoRa.begin(868E6)) {
Serial.println("LoRa init failed. Check your connections.");
while (true);
}
Serial.println("LoRa init succeeded.");
}
void sendMessage(String outgoing) {
LoRa.beginPacket(); // start packet
LoRa.write(destination); // add destination address
LoRa.write(localAddress); // add sender address
LoRa.write(msgCount); // add message ID
LoRa.write(outgoing.length()); // add payload length
LoRa.print(outgoing); // add payload
LoRa.endPacket(); // finish packet and send it
msgCount++; // increment message ID
}
void loop() {
if (millis() - lastSendTime > interval) {
String message = "HeLoRa!";
sendMessage(message);
Serial.println("Sending " + message);
lastSendTime = millis();
display.clear();
display.drawString(0, 0, String(lastSendTime));
display.display();
}
}
I also tried to set the values after LoRa.begin(), but then nothing is received by the receiver.
NOTE: It can't be the board itself, since I have several and have tried it with each one.

SPI Communication between STM32 and ADXL345

I am trying to use the SPI communication to read data from the ADXL345 accelerometer. I configured the different pins and SPI in master mode, and tried reading the x, y and z axis accelerations.
My issue is that the SPI readings are always 0. I tried debugging to find the issue and I realized that RXNE is never set even though I'm transmitting data and I don't really get why.
I'm using STM32F103 Board.
Here's my code:
#include "Driver_GPIO.h"
#include "stm32f10x.h"
uint8_t RxData[6];
int x,y,z;
float x_acc,y_acc,z_acc;
void GPIO_Config (void)
{
MyGPIO_Struct_TypeDef NSS={GPIOA,4,Out_OD}; // Output Open Drain
MyGPIO_Struct_TypeDef SCK={GPIOA,5,AltOut_Ppull}; // Alternate Output Push-Pull
MyGPIO_Struct_TypeDef MISO={GPIOA,6,In_Floating}; // Input Floating
MyGPIO_Struct_TypeDef MOSI={GPIOA,7,AltOut_Ppull}; // Alternate Output Push-Pull
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //enable GPIOA clk
MyGPIO_Init(&NSS);
MyGPIO_Init(&SCK);
MyGPIO_Init(&MISO);
MyGPIO_Init(&MOSI);
}
void SPI_Enable (void)
{
SPI1->CR1 |= (SPI_CR1_SPE); // SPE=1, Peripheral enabled
}
void SPI_Disable (void)
{
SPI1->CR1 &= ~(SPI_CR1_SPE); // SPE=0, Peripheral Disabled
}
void CS_Enable (void)
{
GPIOA->BSRR |= GPIO_BSRR_BR9;
}
void CS_Disable (void)
{
GPIOA->BSRR |= GPIO_BSRR_BS9;
}
void SPI_Config(void){
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // Enable SPI1 CLock
SPI1->CR1 |= SPI_CR1_CPOL| SPI_CR1_CPHA; // CPOL=1, CPHA=1
SPI1->CR1 |= SPI_CR1_MSTR; // Master Mode
SPI1->CR1 |= (SPI_CR1_BR_0)| (SPI_CR1_BR_1); // BR[2:0] = 400: fPCLK/16, PCLK2 = 72MHz, SPI clk = 3.375MHz
SPI1->CR1 &= ~SPI_CR1_LSBFIRST; // LSBFIRST = 0, MSB first
SPI1->CR1 |= (SPI_CR1_SSM) | (SPI_CR1_SSI); // SSM=1, SSI=1 -> Software Slave Management
SPI1->CR1 &= ~SPI_CR1_RXONLY; // RXONLY = 0, full-duplex
SPI1->CR1 &= ~SPI_CR1_DFF; // DFF=0, 8 bit data
SPI1->CR2 = 0;
}
void SPI_Transmission(uint8_t *data, int size){
uint8_t clear;
//check flag TxE //
int i=0;
while (i<size)
{
while (!((SPI1->SR)&(SPI_SR_TXE))){}; // buffer is empty
*(volatile uint8_t *)&SPI1->DR = data[i];
i++;
}
while (!((SPI1->SR)&(SPI_SR_TXE))){}; // buffer is empty
while (((SPI1->SR)&(SPI_SR_BSY))){}; // buffer not communicating
clear= SPI1->DR; // empty Overrun flag
clear= SPI1->SR;
}
void SPI_Receive (uint8_t *data,int size)
{
while (size)
{
while (((SPI1->SR)&(SPI_SR_BSY))) {}; // buffer not communicating
*(volatile uint8_t *)&SPI1->DR = 0; // dummy data
while (!((SPI1->SR) &(SPI_SR_RXNE))){};
// buffer is not empty
*data++= *(volatile uint8_t *)&SPI1->DR;
size--;
}
}
void adxl345_write (uint8_t address, uint8_t value)
{
uint8_t data[2];
data[0] = address|0x40; // multibyte write
data[1] = value;
CS_Enable (); // pull the cs pin low
SPI_Transmission (data,2); // write data to register
CS_Disable (); // pull the cs pin high
}
void adxl345_read (uint8_t address, uint8_t *RxData)
{
address |= 0x80; // read operation
address |= 0x40; // multibyte read
CS_Enable (); // pull the pin low
SPI_Transmission (&address,1); // send address
SPI_Receive (RxData,6); // receive 6 bytes data
CS_Disable ();; // pull the pin high
}
void adxl345_init (void)
{
adxl345_write (0x31, 0x01); // data_format range= +- 4g
adxl345_write (0x2d, 0x00); // reset all bits
adxl345_write (0x2d, 0x08); // power_cntl measure and wake up 8hz
}
int main(void)
{
GPIO_Config();
SPI_Config();
SPI_Enable();
adxl345_init();
do{
adxl345_read(0x32,RxData);
x = ((RxData[1]<<8)|RxData[0]); // DATA X0, X1
y = ((RxData[3]<<8)|RxData[2]); // DATA Y0, Y1
z = ((RxData[5]<<8)|RxData[4]); // DATA Z0, Z1
// Scale Factor for Xout, Yout and Zout is 7.8 mg/LSB for a +-4g, 10-bit resolution
// ==> multiply by 0.0078 to get real acceleration values
x_acc= x * 0.0078;
y_acc= y * 0.0078;
z_acc= z * 0.0078;
}while(1);
}
As already stated you have a lot of issues here
Why NSS pin is configured open-drain? Typically CS lines are push-pull. I don't know the schematics, but this is the first time I see an open-drain CS
In GPIO_Config NSS is pin 4, yet pin 9 is toggled from CS_Enable
If F1 series there is separate clocking bit for the alternate functions, it's not enabled
It is also weird that you are telling that RXNE is always zero and the readings returns zero. Your code should stuck in while loops if RXNE stays zero
I will not analyze magic numbers as I do not have time check every number in the RM. But you have many obvious issues.
Deley or readback is required after enabling the peripheral clock. You instantly set the registers which is wrong. Add __DSB(); or readback (for example (void)RCC->APB2ENR;). Same for all peripherals

Speed measurement from lidar sensor for automatic braking system

For a school project I have been working on a system that will automatically brake when there is danger. Only the requirements are more strict (safety) than just using a ping sensor and detecting a fixed distance. I am going to implement the speed of an incoming object as well.
On the internet I found this awesome 100Hz sample Lidar module that's very cheap. It uses UART with 2 header frames (0x59), after that a dataLowbyte and a dataHighbyte. Here is the datasheet for the module.
So I've started inputting coffee and outputting code (in C) on the atmega328P (Arduino).
As you can see here I've set up the code to read the sensor and process the data. The problem is that it gives back weird readings. Like a distance difference when I'm moving further away and when moving closer even though I stated it not to. Does anyone have experience using this module? Or maybe I misread something of the datasheet.
//Includes
//============================================================================================//
#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h>
//============================================================================================//
//Defines
//============================================================================================//
#define F_CPU 16000000 //CPU frequency
#define Baudrate 115200 //UART Baudrate
#define UBRR_VALUE (((F_CPU / (Baudrate * 8))) - 1) //UART Baudrate set in Arduino
// #define SafetyRating 8
// #define sampleTime 0x65 //Time between 2 samples in 10^-4. This value comes from testing (its 1,01ms)
//============================================================================================//
//Enums
//============================================================================================//
enum {Safe, Warning, Danger}State; //Possible States
//============================================================================================//
//Global variables
//============================================================================================//
uint8_t distanceL; //Distance (low value) data taken from the UART buffer coming from Lidar
uint8_t distanceH; //Distance (high value) data taken from the UART buffer coming from Lidar
uint16_t Distance; //Distance combined
uint8_t frameByteCount = 0; //To count which byte in the frame is current
uint16_t Speed; //Speed variable
//volatile uint8_t DangerLevel; //Danger indicator
//Function prototypes
//============================================================================================//
void calcSpeed(uint16_t Measurement); //Function to calculate the speed out of distance readings
void UART_Transmit(uint8_t data); //Funtion to send data via uart
//============================================================================================//
//Interrupts
//============================================================================================//
/*UART receive complete interrupt*/
ISR(USART_RX_vect) //Data taken from the UART buffer
{
uint8_t sample;
sample = UDR0; //Read a sample from the receiver buffer
if(frameByteCount == 3) //If its the 4th byte of the frame
{
frameByteCount = 0; //Reset the counter
distanceH = sample; //Read the distance data high byte
Distance = (8 << distanceH); //Combine the data low and data high
Distance |= distanceL;
calcSpeed(Distance); //Send the data to laptop for debugging purposes
}
if(frameByteCount == 2) //If its the 3rd byte in the frame read the distance data low byte
{
distanceL = sample;
frameByteCount++; //Increment the counter
}
if (sample == 0x59) //If a sample is a header increment a counter
{
frameByteCount++;
}
else if (frameByteCount != 2 && frameByteCount != 3) //If its not a header or distance data byte reset counter
{
frameByteCount = 0;
}
}
//============================================================================================//
//Timers and Counters
//============================================================================================//
/*Timer0 Counter, this decreases the danger level periodically so a really slow approach will not keep incrementing the danger level*/
ISR(TIMER0_OVF_vect)
{
// if (DangerLevel > 0)
// {
// DangerLevel--;
// }
}
//============================================================================================//
//Main
//============================================================================================//
int main(void)
{
DDRB |= 0x02; //For debugging purposes LED pin PB1 (pin 9) as output
UBRR0H = (UBRR_VALUE >> 8); //Setting the Baudrate register high value
UBRR0L = UBRR_VALUE; //Setting the Baudrate register low value
UCSR0A |= (1<<U2X0); //Setting the data sample to double speed to make Baudrate error less
UCSR0C |= (1<<UCSZ01) | (1<<UCSZ00); //Initializing UART, setting frame to 8 data bits
UCSR0B |= (1<<RXCIE0) | (1<<TXEN0) | (1<<RXEN0); //Setting receiver interrupt enable, transmitter enable and receiver enable... Transmitter for debugging purposes
TCCR0A = 0x00; //Timer0 Setup
TCCR0B |= 0x05; //Timer0 clock prescaler to 1024
TIMSK0 |= 0x01; //Timer0 overflow interrupt enable
sei(); //Set interrupts
State = Safe; //Set state to safe
while (1)
{
//checkState(DangerLevel);
}
}
//============================================================================================//
//Functions
//============================================================================================//
/*Calculate the danger level out of distance readings*/
void calcSpeed(uint16_t Measurement)
{
static uint8_t samplenumber = 0; //Sample tracker
static uint16_t value0 = 0; //First sample
static uint16_t value1 = 0; //Second sample
switch(samplenumber) //To store the measurements alternately
{
case 0:
value0 = Measurement; //Store first measurement
samplenumber = 1; //So next measurement goes to a different variable
break;
case 1:
value1 = Measurement; //Store 2nd measurement
samplenumber = 0; //So next measurement goes to a different variable
break;
default:
break;
}
if (samplenumber == 0 && value1 < value0) //When value0 is first and value1 is second and the object is closing in
{
Speed = value0 - value1;
}
else if (samplenumber == 1 && value0 < value1) //When value1 is first and value0 is second and the object is closing in
{
Speed = value1 - value0;
}
else
{
Speed = 0;
}
UART_Transmit(Speed); //I think sending an uint16_t over uint8_t uart is possible because 'Speed' is never greater than 255 when i'm testing it
}
/*Send data over UART when buffer is empty*/
void UART_Transmit(uint8_t data)
{
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) )
;
/* Put data into buffer, sends the data */
UDR0 = data;
}
//============================================================================================//
I found it!
Distance = (8 << distanceH); //Combine the data low and data high
Distance |= distanceL;
Should be:
Distance = (distanceH << 8); //Combine the data low and data high
Distance |= distanceL;

Transmitting 10bit data through The UART of PIC16F877A

I'm beginner to micro controller technology. I want to transmit the 10-bit output I got from an Analog to Digital Conversion, but only 8 bits can be sent via the UART. How can I send 10 bits?
Please help me to write C code to solve this problem. My code so far is given below. The compiler used is XC8.
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
#define _XTAL_FREQ 4000000
#include <stdio.h>
#include <stdlib.h>
#include <htc.h>
void uart_init(void);
void TX(unsigned char TX_BYTE);
void configure_pins();
unsigned char read_input(unsigned char channel);
void main()
{
__delay_ms(2);
while (1) {
TRISB = 0; //configuring portB as output
TRISC = 0;
TRISA = 1;
configure_pins(); //calling methods
unsigned char x = read_input(0);
uart_initialize();
assign_data_to_tx_pin(x);
}
}
void configure_pins(){
ADCON1 = 0b10000000; //The result is right justified
}
unsigned char read_input(unsigned char channel){ // converting the Analog input to digital
ADCON0=0b00000000;
CHS0=0; // AN0 is selected
CHS1=0; // "
CHS2=0; // "
ADON = 1;
GO_DONE = 1;
while (GO_DONE);
ADON = 0;
return ((ADRESH >> 2) + ADRESL); // return the result of conversion
}
void uart_initialize(void) // initializing the UART for data transmission
{
TRISC = 0; //configuring portC as output
TXSTA = 0b100000000;
TXEN = 1; //enable transmission mode
SPEN = 1; //enable UART
BRGH = 0; //enable low baud
SPBRG = 6; //set baud rate as 9600
SYNC = 0; //enable asynchronous transmission
RCIE = 1;
GIE = 1;
PEIE = 1;
}
void assign_data_to_tx_pin(unsigned char converted_data) { // assigning the data to the Tx pin for transmission
while(!TRMT) {
unsigned char a = converted_data;
TXREG = a;
TXREG = a >> 2;
PORTCbits.RC6 = TXREG;
__delay_ms(100); // Delay
}
}
Typical UARTs do not allow for more than 8 bits of data per transmission. Some allow 9. Sending 10 bits may be available on select UARTS using 9 bits and controlling the parity, but that is rare.
Instead recommend to send the data as 2 transmission with a bit set aside to denote which half is sent.
Send_ADC(void){
ADCON0=0b00000000;
CHS0=0; // AN0 is selected
CHS1=0; // "
CHS2=0; // "
ADON = 1;
GO_DONE = 1;
while (GO_DONE);
ADON = 0;
unsigned adc10 = ((ADRESH >> 2) + ADRESL);
assign_data_to_tx_pin((adc10 % 32) * 2 + 0); // 00lllll0
assign_data_to_tx_pin((adc10 / 32) * 2 + 1); // 00hhhhh1
}
On receiver side, insure bytes received are in the proper byte order. This will re-construct the received data in the proper order, even if reception does not start in phase or if a byte was lost in communication.
// return 0: success, else 1
int ReadSerialADC(unsigned *data) {
unsigned adc;
unsigned low = read_from_comport();
if (low %2) return 1;
low /= 2;
unsigned high = read_from_comport();
if (high %2 == 0) return 1;
high /= 2;
*data = high * 32 + low;
return 0;
}
You are reading a 10-bit ADC result with like this
return ((ADRESH>>2)+ADRESL);
But the function is return unsigned char, it should be unsigned int
unsigned int read_input(unsigned char channel)
and the calling function is also throwing away two bits with
unsigned char x=read_input(0);
which should be
unsigned int x=read_input(0);
Having read a 10-bit value into a (presumably) 16-bit variable, you now have to transmit it to the serial port. Let's do this by sending the most significant 8 bits first.
TX (x >> 8);
TX (x & 0xFF);
Then at the receiver end you read the two bytes and put them back together
unsigned adcval = RX() << 8;
adcval |= RX();

AVR Butterfly UART - can't receive data

I am using the UART of Atmega169/AVR Butterfly for transmission to another board, baudrate 56700, no parity, 1 stopbit, no flow control. The oscillator is running at 7,3768Mhz (checked). I can transmit data successfully (checked with the other board and PC/HyperTerminal), but not receive any data - when running the debugger the configuration bits are all set correctly, but RXC is false constantly - I also checked if I can send data to myself (connected TXD to RXD and grounded), but without success. (Tried with ISR as well as polling)
Below are the relevant parts of the code, I hope you can deal with it - PORTB is used as output for testing with the oscilloscope (I know I could just use one pin, but there is nothing else on PORTB right now):
int main(void){
OSCCAL_Calibrate(); // calibrate the internal oscillator
int UBRR_VAL = ((F_CPU)/(BAUD*16)-1);
UART_Init(UBRR_VAL);
DDRB |= 0xFF;
PORTB = 0;
testCharSend();
while(1);
return 0;
}
void testCharSend()
{
char i = 'x';
while(1){
Uart_Tx(i);
}
}
void UART_Init(unsigned int baudrate)
{
// Set baud rate
UBRRH = (unsigned char)(baudrate>>8);
UBRRL = (unsigned char)baudrate;
UCSRA = 0;
// Enable receiver and transmitter
UCSRB = (1<<RXEN)|(1<<TXEN);
// Async. mode, 8bit, No parity, 1 stop bit (like CC2540)
UCSRC = (0<<UMSEL)|(0<<UPM0)|(0<<USBS)|(3<<UCSZ0)|(0<<UCPOL);
// enable receive interrupt
UCSRB |= (1<<RXCIE);
// flush UART
UART_Flush();
}
void UART_Flush( void )
{
unsigned char dummy;
while ( UCSRA & (1<<RXC) ) dummy = UDR;
}
void Uart_Tx(char data)
{
while (!(UCSRA & (1<<UDRE)));
UDR = data;
}
ISR (USART0_RX_vect)
{
PORTB ^= 0xFF;
char c = UDR;
}
OK, I tested the connections with an oscilloscope, the RXD line on the board was broken, switched the board and now it's working, so the code above is valid!

Resources