I am using LPC2148 with SIM800L on UART1 using interrupt. When I use memset(buff, 0 , sizeof(buff)); in while(1) at first the program works fine but when while(1) loop runs again it prints error over and over but when I comment the memset(buff, 0, sizeof(buff)); it works fine.
So why it is not receiving the data on using memset function?
#include <lpc214x.h>
#include <stdio.h>
#include <string.h>
__irq void uart1_interrupt(void);
void init_uart1(void); //////initialize uart1
void uart1_write(char data); //////send char on uart1
void uart1_send_string(char *str);//////send string on uart1
void Uart0_string(char *str); //////send string on uart0
void U0write(char data); //////send
char on uart0
void init_uart0(void); //////initialize uart0
void pll_init(void);
void timer_init(void);
void delay_ms(unsigned int ms);
//void clear_data(); /////clear buffer
char buff[160];
//char sms_receive[60];
int i, a = 0;
int main(void)
{
pll_init();
timer_init();
init_uart0();
//init_uart1();
VICVectAddr0 = (unsigned) uart1_interrupt; /////attach interrupt routine
VICVectCntl0 = (1<<5)|7; ////enable uart irq slot for uart1
VICIntEnable |= (1<<7); ////enable uart1 interrupt
VICIntSelect = 0x00000000;
init_uart1();
Uart0_string("gsm test\r\n");
delay_ms(3000);
while(1)
{
uart1_send_string("AT\r\n");
delay_ms(400);
if(strstr(buff,"OK"))
{
Uart0_string(buff);
}
else
{
Uart0_string("ERROR ");
}
delay_ms(3000);
uart1_send_string("AT+CNMI=?\r\n");
delay_ms(400);
if(strstr(buff,"+CNMI"))
{
Uart0_string(buff);
}
else
{
Uart0_string("ERROR ");
}
delay_ms(3000);
//clear_data();
memset(buff, 0 , sizeof(buff));
}
}
/*void clear_data()
{
for(i = 0; i<=sizeof(buff); i++)
{
buff[i] = 0;
}
}*/
__irq void uart1_interrupt(void)
{
buff[a] = U1RBR;
a++;
VICVectAddr = 0x00;
}
void init_uart1(void)
{
PINSEL0 = PINSEL0 | 0x00050000; ////UART1 pin selection
U1LCR = 0x83; ////8 bit, no parity, 1 stop bit, DLAB - 1
U1DLL = 0x56; ////86 in decimal
U1DLM = 0x00;
U1FDR = 0xF2;
U1LCR &= 0x0f; /////setting DLAB bit to 0
U1IER = 0x01; ////enable interrupt
}
void uart1_write(char data)
{
U1IER = 0x00;
while(!(U1LSR &(1<<5))); ////U1LSR contains THRE status bit, wait while THR is empty
U1THR = data;
U1IER = 0x01;
}
void uart1_send_string(char *str)
{
U1IER = 0x00;
while(*str != '\0')
{
uart1_write(*str++);
}
U1IER = 0x01;
}
/*char uart1_receive()
{
while(!(U1LSR & (1<<0)));
return U1RBR;
}*/
void init_uart0()
{
PINSEL0 = 0x00000005; ////selects TxD P0.0 and RxD P0.1
U0LCR = 0x83; ////8 bit, no parity 1 stop bit, DLAB = 1
U0DLL = 0x56; //// 86 in decimal
U0DLM = 0x00;
U0FDR = 0xF2; ////MULVAL and DIVADDVAL values
U0LCR &= 0x0F;
}
void U0write(char data)
{
while(!(U0LSR & (1<<5))); ///////wait till THR is not empty
U0THR = data; /////// write data to Transmit in U0THR
}
void Uart0_string(char *str)
{
while(*str != '\0')
{
U0write(*str++);
}
}
void pll_init(void)
{
PLL0CON = 0x01; /////enable PLL////
PLL0CFG = 0x24; /////configure PLL/////
PLL0FEED = 0xAA; //////feed sequence/////
PLL0FEED = 0x55; //////feed sequence/////
while(!(PLL0STAT & 0x00000400)); ///is locked////
PLL0CON = 0x03; ////connect PLL////
PLL0FEED = 0xAA;
PLL0FEED = 0x55;
//VPBDIV = 0x01; /////// PCLK = CCLK = 60MHz
VPBDIV = 0x00; /////// PCLK = 60/4 = 15MHz
}
void timer_init(void)
{
//T0TCR = 0x00;
T0CTCR = 0x0; ////selection of timer mode with every rising pclk edge
T0PR = 14999; ////prescale register value will generate 1 ms at 60MHz
T0TCR = 0x02; ////reset the timer counter and prescale couter
}
void delay_ms(unsigned int ms)
{
//T0TC = 0x00000000;
T0TCR = 0x02; /////reset timer. Timer should be reset
T0TCR = 0x01; /////enable timer to generate delay
T0MR0 = ms;
while(T0TC < T0MR0); /////wait until Timer counter register reaches desired delay
T0TCR = 0x00; /////disable timer
}
output when using memset(buff, 0, sizeof(buff))
gsm test
AT
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
ERROR ERROR ERROR ERROR
output when not using memset(buff, 0 , sizeof(buff)). I want to achive this output using memset(buff, 0 , sizeof(buff))
gsm test
AT
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
AT+CNMI=?
+CNMI: (0-3),(0-3),(0,2),(0,1),(0,1)
OK
AT
OK
a is reset only once at the start. The interrupt increments a on every character. When your main loop repeats, the ISR (interrupt service routine) will increment it further, finally overwriting the memory after buf.
That's why without memset() you get ever repeating the same result. The contents of buf is always checked from its beginning, but the received answers are stored one after the other.
Reset a on every entry in the loop, that should help.
However, writing (and/or reading) to the same variable from more than one thread is calling for disaster. Look for some lessons about multi-threaded programming. Yes, using interrupts is programming with multiple threads.
The while(1) loop in the main function does not make any input to char buff[160]. That is done only in the interrupt handler. So when you use memset to fill the buffer, it then begins with the string terminator character '\0' and the statements
if(strstr(buff,"OK"))
and
if(strstr(buff,"+CNMI"))
are false – NULL means no match was found – and so the error messages are output.
Note too that in the interrupt handler __irq void uart1_interrupt(void) you have
buff[a] = U1RBR;
a++;
but nowhere is a limited or reset or wrapped to prevent buffer overrun. So there is a disaster waiting to happen.
Related
I am using a PIC 18F46K22 in SPI master mode to communicate with a Waveshare 1.54" ePaper Module. The FOSC frequency is 8Mhz internal and SPI configuration is FOSC/4. So when I check the output on logic-analyzer some output bits are differ from expected. And there is some deviation in SCL.
#include <xc.h>
#include "config.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "main.h"
//#define _XTAL_FREQ 8000000
#define SPI1_DUMMY_DATA 0x0
#define SPI_RX_IN_PROGRESS 0x0
#define MY_BUFFER_SIZE 25
extern UBYTE EPD_Init(const unsigned char* lut);
unsigned char myWriteBuffer[100]="Hi I'm master..";
uint8_t myReadBuffer[100];
uint8_t total;
uint8_t temp;
uint8_t my_data = 0x58;
void UART_Init(void)
{
//69
SPBRG2 = 69;
TXSTA2bits.BRGH = 1;
BAUDCON2bits.BRG16 = 1; // Divisor at 8 bit
TRISDbits.TRISD6 = 0;
TRISDbits.TRISD7 = 1;
RCSTA2bits.SPEN = 1; // Enable serial port
TXSTA2bits.SYNC = 0; // Async operation
TXSTA2bits.TX9 = 0; // No tx of 9th bit
RCSTA2bits.RX9 = 0; // No rx of 9th bit
TXSTA2bits.TXEN = 1; // Enable transmitter
RCSTA2bits.CREN = 1; // Enable receiver
}
void UART_Putch(unsigned char bt)
{
while (!PIR3bits.TX2IF); // hold the program till TX buffer is free
TXREG2 = bt; //Load the transmitter buffer with the received value
}
void UART_Print(unsigned const char *ptr)
{
while (*ptr != 0)
{
UART_Putch(*ptr++);
}
}
unsigned char UART_getch() {
unsigned char temp;
if (RCSTA2bits.OERR) // check for Error
{
RCSTA2bits.CREN = 0; //If error -> Reset
//__delay_ms(10);
RCSTA2bits.CREN = 1; //If error -> Reset
}
while (!PIR3bits.RC2IF); // hold the program till RX buffer is free
temp = RCREG2;
return temp; //receive the value and send it to main function
}
void main()
{
ANSELA = 0;
ANSELB = 0;
ANSELC = 0;
ANSELD = 0;
TRISBbits.TRISB0 = 0; //RST Pin OUTPUT
TRISBbits.TRISB1 = 0; //DC Pin OUTPUT
TRISBbits.TRISB2 = 0; //CS Pin OUTPUT
TRISBbits.RB3 = 1; //BUSY Pin INPUT
// int i;
TRISD =0;/* PORT initialize as output */
EPD_RST_PIN = 0;
EPD_DC_PIN = 0;
//OSCCON = 0x72; /* Use internal osc. frequency 16 MHz */
OSCCONbits.SCS = 0b10; //Frequency & PLL SETUP
OSCCONbits.IRCF = 0b110; //8 MHz
while (!OSCCONbits.HFIOFS);
OSCTUNEbits.PLLEN = 0; //PLL disable
UART_Init();
SPI_Init_Master(); /* Initialize SPI communication as a master */
if(EPD_Init(lut_full_update) != 0) {
UART_Print("e-Paper init failed\r\n");
while(1);
}
UART_Print("e-Paper init\r\n");
for(uint8_t i = 0; i < 10; i++){
__delay_ms(10);
}
EPD_Clear();
UART_Print("e-Paper cleared\r\n");
for(uint8_t i = 0; i < 10; i++){
__delay_ms(50);
}
while(1)
{
// total = 0;
// //do
// //{
// LATAbits.LATA5=0;
// //total = SPI1_Exchange8bitBuffer(SPI1_DUMMY_DATA, MY_BUFFER_SIZE, &myReadBuffer[total]);
// total = SPI1_Exchange8bit(my_data);
//
// LATAbits.LATA5=1;
// __delay_ms(500);
// __delay_ms(500);
// // Do something else...
//
// //} while(total < MY_BUFFER_SIZE);
// //while(1);
//
// EPD_Clear();
//
// __delay_ms(500);
}
}
void SPI_Init_Master()
{
/* PORT definition for SPI pins*/
TRISCbits.TRISC4 = 1; /* RB0 as input(SDI) */
TRISCbits.TRISC3 = 0; /* RB1 as output(SCK) */
// TRISBbits.TRISB2 = 0; /* RA5 as a output(SS') */
TRISCbits.TRISC5 = 0; /* RC7 as output(SDO) */
/* To initialize SPI Communication configure following Register*/
EPD_CS_PIN = 1;
SSP1STAT=0x00; /* Data change on rising edge of clk , BF=0*/
SSP1CON1=0x20; /* Slave mode,Serial enable, idle state high for clk */
PIR1bits.SSP1IF=0;
/* Disable the ADC channel which are on for multiplexed pin
when used as an input */
ADCON0=0; /* This is for de-multiplexed the SCL
and SDI from analog pins*/
ADCON1=0x0F; /* This makes all pins as digital I/O */
}
uint8_t SPI1_Exchange8bit(uint8_t data)
{
// Clear the Write Collision flag, to allow writing
SSP1CON1bits.WCOL = 0;
SSP1BUF = data;
while(SSP1STATbits.BF == SPI_RX_IN_PROGRESS)
{
}
return (SSP1BUF);
}
uint8_t SPI1_Exchange8bitBuffer(uint8_t *dataIn, uint8_t bufLen, uint8_t *dataOut)
{
uint8_t bytesWritten = 0;
if(bufLen != 0)
{
if(dataIn != NULL)
{
while(bytesWritten < bufLen)
{
if(dataOut == NULL)
{
SPI1_Exchange8bit(dataIn[bytesWritten]);
}
else
{
dataOut[bytesWritten] = SPI1_Exchange8bit(dataIn[bytesWritten]);
}
bytesWritten++;
}
}
else
{
if(dataOut != NULL)
{
while(bytesWritten < bufLen )
{
temp = SPI1_Exchange8bit(SPI1_DUMMY_DATA);
if(temp!=SPI1_DUMMY_DATA)
{
UART_Putch(temp); //uart print
dataOut[bytesWritten] = temp;
bytesWritten++;
}
__delay_ms(5);
}
}
}
}
return bytesWritten;
}
Compare your logic analyser SCK and MOSI timing with that specified for the part at https://www.waveshare.com/wiki/1.54inch_e-Paper_Module:
Note that the MOSI (SDIN) state must be stable on the rising edge of SCK (SCLK). In your case the MOSI transitions are synchronous with the rising edge, and you have a clock transition before the MOSI has the correct D7=0 state. SPI timing is defined by both clock polarity and clock phase - giving four possible clock modes. Compare the Waveshare timing diagram with the 18F46K22 datasheet:
The Waveshare diagram suggests that either CKP=1/CKE=0, or CKP=0/CKE=1 may be used, you have:
SSP1STAT=0x00 ;
SSP1CON1=0x20 ;
Which is CKP=0/CKE=0 (which correlates with your logic analyser trace).
You need on of either:
SSP1STAT=0x20 ; // CKE=1
SSP1CON1=0x20 ; // CKP=0
or
SSP1STAT=0x00 ; // CKE=0
SSP1CON1=0x30 ; // CKP=1
Since idle state (controlled by CKP) of SCK is a don't-care, I suggest leaving that as-is and using the first suggestion - that seems more intuitive somehow.
Note also that your logic analyser must also be set to the same phase/polarity clock mode in order for its presentation of the data to be correct.
i'm monitorating heart rate by the MAX30100(https://img.filipeflop.com/files/download/Datasheet_MAX30100.pdf) using the MCU STM32F4. I'm trying read the IR and RED data from the FIFO, but all returns are ZERO. The method MAX30100_Get_Num_Samples() returns 8. I modeled the code using the pseudo code from datasheet of MAX30100. I tried several solutions for my problem but doesn't work. I dont know if i'm following the right way to get data from the FIFO. My code:
I2C_HandleTypeDef hi2c3; //i2c used
uint16_t RED[50] = {0}, IR[50] = {0}; //buffers for RED and IR
uint8_t buffOximeter[5];
char buffer[32];
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C3_Init();
MX_USB_DEVICE_Init();
MAX30100_Init();
while (1)
{
uint8_t numSamples = MAX30100_Get_Num_Samples();
MAX30100_Read_HeartBeat(numSamples);
for(int i = 0; i < numSamples; i++)
{
sprintf(buffer, "Amostra %d: %d / %d\n\r", i , IR[i], RED[i]);
CDC_Transmit_FS((char*)buffer, 50);
}
}
}
static void MX_I2C3_Init(void)
{
hi2c3.Instance = I2C3;
hi2c3.Init.ClockSpeed = 400000;
hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c3.Init.OwnAddress1 = 0;
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c3) != HAL_OK)
{
Error_Handler();
}
}
void MAX30100_Init(void)
{
HAL_I2C_Mem_Write(&hi2c3,0xAE,0x06,1,0x02,1,1000); //set heart rate mode
HAL_I2C_Mem_Write(&hi2c3,0xAE,0x09,1,0xFF,1,1000); //i50 ledCurrent
uint8_t sr = 0x01, pw = 0x3;
HAL_I2C_Mem_Write(&hi2c3,0xAE,0x07,1,(sr<<2)|pw,1,1000); //sr100, pw1600
HAL_Delay(50);
}
void MAX30100_Read_HeartBeat(uint8_t num)
{
for(int i=0;i<num;i++)
{
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAE,1,1000); //adress + write mode
HAL_I2C_Master_Transmit(&hi2c3,0x57,0x02,1,1000); //send fifo_wr_ptr
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAF,1,1000); //adress + read mode
uint8_t data;
HAL_I2C_Master_Receive(&hi2c3,0x57,&data,1,1000); //read fifo_wr_ptr
HAL_Delay(100); //STOP
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAE,1,1000); //adress + write mode
HAL_I2C_Master_Transmit(&hi2c3,0x57,0x05,1,1000); //send adress fifo data
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAF,1,1000); //adress + read mode
HAL_I2C_Mem_Read(&hi2c3,0x57,0x05,1,&buffOximeter,4,1000); //read fifo data
IR[i] = (buffOximeter[0] << 8) | buffOximeter[1];
RED[i] = (buffOximeter[2] << 8) | buffOximeter[3];
HAL_Delay(100); //STOP
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAE,1,1000); //adress + write mode
HAL_I2C_Master_Transmit(&hi2c3,0x57,0x04,1,1000); //send adress fifo_rd_ptr
HAL_Delay(100);
}
}
int MAX30100_Get_Num_Samples(void)
{
uint8_t wrPtr, rdPtr;
HAL_I2C_Mem_Read(&hi2c3,0x57,0x02,1,&wrPtr,1,1000);
HAL_Delay(50);
HAL_I2C_Mem_Read(&hi2c3,0x57,0x04,1,&rdPtr,1,1000);
HAL_Delay(50);
return (abs( 16 + wrPtr - rdPtr ) % 16);
}
connect the interrupt output pin (pin 13 active low) to an interrupt control pin on the cpu.
setup your cpu to be interrupted when the device indicates some event ready
Then, still in your interrupt handler function, read register 0 and determine which data is ready,.
the referenced datasheet, approx page 14 lists the order of communication events needed. Note that the posted code is NOT following the specified order of communication events
page 16, register 7, indicates how to initialize the SPO2 for the desired mode of operation
I'm able to receive with the following code, but unfortunately, nothing is sent back. What am I doing wrong?
#include <pic18f25k80.h>
#include "config.h"
#include <usart.h>
int i = 0;
unsigned char MessageBuffer[200];
void main() {
OSCCONbits.IRCF = 0b110; // 8MHz
TRISB6 = 0; // TX set as output
TRISB7 = 0; // RX set as output
// Clear TX interrupt
// Set RX interrupt
// 8-bit Asynch. mode
// BRGH = 1 = high baud mode
// 51 = ((8MHz/baud)/16)-1 with baud = 9600
Open2USART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE
& USART_EIGHT_BIT & USART_BRGH_HIGH, 51 );
RC2IF = 0; // reset RX2 flag
RC2IP = 0; // not high priority
RC2IE = 1; // Eneble RX2 interrupt
INTCONbits.PEIE = 1; // enable peripheral interrupts
INTCONbits.GIE = 1; // enable interrupts
RCSTA2bits.SPEN = 1; // enable USART
while(1){
}
}
void interrupt ISR () {
if(PIR3bits.RC2IF == 1) {
if(i<200) { // buffer size
MessageBuffer[i] = Read2USART(); // read byte from RX reg
if (MessageBuffer[i] == 0x0D) { // check for return key
puts2USART(MessageBuffer);
for(;i>0;i--)
MessageBuffer[i] = 0x00; // clear array
i=0;
return;
}
i++;
RC2IF = 0; // clear RX flag
} else {
puts2USART(MessageBuffer);
for(;i>0;i--)
MessageBuffer[i] = 0x00; // clear array
i = 0;
return;
}
}
}
I'm transmitting the 0x41 hex code, I checked with the scope and see that is is being received. And according to the code I have, an echo of the received data should be sent back. When I check the TX pin, nothing is happening.
Add USART_CONT_RX to Open2USART to enable continuous receive.
Also, it's a good idea to do the minimum necessary in the interrupt service routine. Consider something like:
void interrupt ISR () {
char data;
if(PIR3bits.RC2IF == 1) {
data = Read2USART(); // always read byte from RX reg (clears RC2IF)
if(i<200) { // buffer size
MessageBuffer[i] = data; // read byte from RX reg
i++;
}
else{
// flag buffer full error
}
}
}
and doing the rest of what you are doing in the while(1) loop.
How can I send the string "MY STRING" from a master pic to a slave?
I'm using MicroC RS-485 library example:
http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/rs-485_library.htm
Im trying to send string from master to slave: and seting dat[7] = "my string"; expecting dat[7] on slave with my string but im geting empty value...
Original code in the link bottom.
Master
char dat[10]; // buffer for receving/sending messages
char i,j;
sbit rs485_rxtx_pin at RC2_bit; // set transcieve pin
sbit rs485_rxtx_pin_direction at TRISC2_bit; // set transcieve pin direction
// Interrupt routine
void interrupt() {
RS485Master_Receive(dat);
}
void main(){
long cnt = 0;
ANSEL = 0; // Configure AN pins as digital I/O
ANSELH = 0;
C1ON_bit = 0; // Disable comparators
C2ON_bit = 0;
PORTB = 0;
PORTD = 0;
TRISB = 0;
TRISD = 0;
UART1_Init(9600); // initialize UART1 module
Delay_ms(100);
RS485Master_Init(); // initialize MCU as Master
dat[0] = 0xAA;
dat[1] = 0xF0;
dat[2] = 0x0F;
dat[4] = 0; // ensure that message received flag is 0
dat[5] = 0; // ensure that error flag is 0
dat[6] = 0;
dat[7] = "MY STRING";
RS485Master_Send(dat,1,160);
RCIE_bit = 1; // enable interrupt on UART1 receive
TXIE_bit = 0; // disable interrupt on UART1 transmit
PEIE_bit = 1; // enable peripheral interrupts
GIE_bit = 1; // enable all interrupts
while (1){
// upon completed valid message receiving
// data[4] is set to 255
cnt++;
if (dat[5]) { // if an error detected, signal it
PORTD = 0xAA; // by setting portd to 0xAA
}
if (dat[4]) { // if message received successfully
cnt = 0;
dat[4] = 0; // clear message received flag
j = dat[3];
for (i = 1; i <= dat[3]; i++) { // show data on PORTB
PORTB = dat[i-1];
} // increment received dat[0]
dat[0] = dat[0]+1; // send back to master
Delay_ms(1);
RS485Master_Send(dat,1,160);
}
if (cnt > 100000) {
PORTD ++;
cnt = 0;
RS485Master_Send(dat,1,160);
if (PORTD > 10) // if sending failed 10 times
RS485Master_Send(dat,1,50); // send message on broadcast address
}
}
}
Slave:
char dat[9]; // buffer for receving/sending messages
char i,j;
sbit rs485_rxtx_pin at RC2_bit; // set transcieve pin
sbit rs485_rxtx_pin_direction at TRISC2_bit; // set transcieve pin direction
// Interrupt routine
void interrupt() {
RS485Slave_Receive(dat);
}
void main() {
ANSEL = 0; // Configure AN pins as digital I/O
ANSELH = 0;
C1ON_bit = 0; // Disable comparators
C2ON_bit = 0;
PORTB = 0;
PORTD = 0;
TRISB = 0;
TRISD = 0;
PORTA = 0;
TRISA = 0;
UART1_Init(9600); // initialize UART1 module
Delay_ms(100);
RS485Slave_Init(160); // Intialize MCU as slave, address 160
dat[4] = 0; // ensure that message received flag is 0
dat[5] = 0; // ensure that message received flag is 0
dat[6] = 0; // ensure that error flag is 0
RCIE_bit = 1; // enable interrupt on UART1 receive
TXIE_bit = 0; // disable interrupt on UART1 transmit
PEIE_bit = 1; // enable peripheral interrupts
GIE_bit = 1; // enable all interrupts
while (1) {
if(dat[7]=="MY STRING"){
RCA0_bit = 1;
}
if (dat[5]) { // if an error detected, signal it by
PORTD = 0xAA; // setting portd to 0xAA
dat[5] = 0;
}
if (dat[4]) { // upon completed valid message receive
dat[4] = 0; // data[4] is set to 0xFF
j = dat[3];
for (i = 1; i <= dat[3];i++){
PORTB = dat[i-1];
}
dat[0] = dat[0]+1; // increment received dat[0]
Delay_ms(1);
RS485Slave_Send(dat,1); // and send it back to master
}
}
}
char dat[9]; defines an array of 9 bytes, so dat[7] = "MY STRING"; will only store a truncated address not the actual string. memcpy can be used to copy strings from one buffer to another.
see: http://www.cplusplus.com/reference/cstring/memcpy/
dat[7]=="MY STRING" will not work as your comparing the 2 byte address of the string literal "MY STRING" with the single byte stored at dat[7]. If you need to compare strings for differences, strcmp works.
see: http://www.cplusplus.com/reference/cstring/strcmp/
I am running a C program on an AVR chip. Whenever a serial signal is heard, it runs the serial interrupt ISR (USART_RX_vect). In this method it should turn on change to = 1;. Then in my main while loop, it should clear the LCD and display it and then set change = 0 again.
This is to stop it continually doing the calulations, and displaying the result on the LCD a million times a minute..
However, when the interrupt method changes the change variable to 1, it does not seem to change it "globally" and in the main method it is always 0..
There is a bit of stuff in here that is for debugging purposes.
/* LCD DEFINES */
#define LED PB5
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)
/* UART SERIAL DEFINES */
#define F_CPU 16000000UL
#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1
#define STARTCHAR 'R'
#define ENDCHAR 'E'
char reading;
char inputBuffer[12];
char readStatus;
uint8_t position;
int change;
char output;
int result;
struct Axis
{
uint8_t axisNumber;
uint16_t position;
uint16_t oldPosition;
} axis1, axis2, axis3;
/* SETUP UART */
void USART_Init( unsigned int ubrr)
{
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
void USART_Transmit( unsigned char data )
{
UDR0 = data;
}
unsigned char USART_Receive( void )
{
return UDR0;
}
/*****************************************************************/
int main(void)
{
/* INITALISE SERIAL */
USART_Init(MYUBRR);
/* Turn on Receive Complete Interrupt */
UCSR0B |= (1 << RXCIE0);
/* Turn On GLobal Interrupts */
sei();
position = 0;
change = 0;
/* Initialise LCD */
lcd_init(LCD_DISP_ON); /* Initialize display, cursor off. */
lcd_clrscr();
lcd_puts("READY");
//Turn on LED 13
set_output(PORTB,LED);
output_low(PORTB,LED);
while (1) /* Loop forever */
{
if (change == 1)
{
//If not reading, display the result on the LCD display.
axis1.position = (inputBuffer[0]<< 8) | inputBuffer[1];
axis2.position = (inputBuffer[2]<< 8) | inputBuffer[3];
axis3.position = (inputBuffer[4]<< 8) | inputBuffer[5];
char axis1Printout[12];
char axis2Printout[12];
char axis3Printout[12];
sprintf(axis1Printout,"%u ", axis1.position);
sprintf(axis2Printout,"%u ", axis2.position);
sprintf(axis3Printout,"%u ", axis3.position);
char output[40] = "";
strcat(output, axis1Printout);
strcat(output, axis2Printout);
//strcat(output, axis3Printout);
lcd_clrscr(); /* Clear the screen*/
lcd_puts(output);
_delay_ms(300);
change = 0;
}
}
}
/* INTERRUPTS */
ISR (USART_RX_vect)
{
change = 1;
unsigned char input = USART_Receive();
if (input == 'R')
{
readStatus = 0; //Reading
position = 0;
}
else if ((input != 'E') && (position < 12) && (position > -1))
{
inputBuffer[position] = input;
position++;
}
else if (input == 'E')
{
readStatus = 1; //Stop Reading
position = -1;
output_high(PORTB,LED);
}
}
You need to declare change using the volatile keyword:
volatile int change;
This tells the two 'threads' (main execution loop and your ISR code) to not 'cache' the value in a register, but always retrieve it from memory.
Edit: There's another problem with the code - in your main loop, by the time you set changed to 0, you may have already had another interrupt which should have triggered your loop to run again. The easy-but-not-guaranteed fix is to immediately set changed to 0 straight after you check it. The proper way would be to use a lock - but depending on your situation, the first option might do.
Make the variable declaration volatile to ensure that a changed value is written imediately to the variable in memory.
An object shared by an interrupt handler and the application code should be qualified as volatile in the declaration.
Without the qualifier, the implementation can assume the object cannot change unexpectedly in the application code and can cache the variable (in a register for example) for optimizations while executing the application code.