How do I copy values from one integer array into another integer array using only the keyboard to fill them? - c

I am trying to store values received from a non-blocking UART protocol. I enter characters from my keyboard and they are stored in an array called buffer that holds the value. I then want to fill a new array called newbuffer using the value from buffer array and then clear the value in buffer array so it is ready to receive another value from the keyboard.
Here is my initialization:
uint8_t buffer[2] = {0}; //initialize array for receiving keyboard input
uint8_t newbuffer[256] = {0}; //initialize array to store keyboard input from buffer array
int i = 0; //array index variable
UartHandle.Instance = USARTx;
UartHandle.Init.BaudRate = 9600;
UartHandle.Init.WordLength = UART_WORDLENGTH_9B;
UartHandle.Init.StopBits = UART_STOPBITS_1;
UartHandle.Init.Parity = UART_PARITY_EVEN;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle.Init.Mode = UART_MODE_TX_RX;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
Here is the callback routine after I have entered my first character. I could really use some help with this part!!!
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//Prevent unused argument(s) compilation warning
UNUSED(huart);
for (i = 0; i < sizeof(newbuffer); i++)
{
newbuffer[i] = buffer[0]; //put value entered from keyboard into newbuffer array
memset(buffer, 0, sizeof(buffer)); //clear buffer array for next value
HAL_UART_Receive_IT (&UartHandle, buffer, 1); //call interrupt that handles entering keyboard values
}
printf("%d", newbuffer);
}
This is the interrupt function for getting keyboard values, in case you need to see that.
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
uint16_t *tmp;
/* Check that a Rx process is ongoing */
if (huart->RxState == HAL_UART_STATE_BUSY_RX)
{
if (huart->Init.WordLength == UART_WORDLENGTH_9B)
{
tmp = (uint16_t *) huart->pRxBuffPtr;
if (huart->Init.Parity == UART_PARITY_NONE)
{
*tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
huart->pRxBuffPtr += 2U;
}
else
{
*tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
huart->pRxBuffPtr += 1U;
}
}
else
{
if (huart->Init.Parity == UART_PARITY_NONE)
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
}
else
{
*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
}
}
if (--huart->RxXferCount == 0U)
{
/* Disable the UART Data Register not empty Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
/* Disable the UART Parity Error Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_PE);
/* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);
/* Rx process is completed, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx complete callback*/
huart->RxCpltCallback(huart);
#else
/*Call legacy weak Rx complete callback*/
HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
return HAL_OK;
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
THANKS IN ADVANCE :)

Have you realized that you are copying exactly 1 byte in the for loop inside HAL_UART_RxCpltCallback, whereas array buffer is two bytes in size ?
This sentence: newbuffer[i] = buffer[0]; is just copying the first byte.
If you are reading from the keyboard you are probably getting scan codes. Scan codes are not all one byte, but many of them. Depending on the keys they can be up to three bytes: https://en.wikipedia.org/wiki/Scancode.

I solved the problem. The issue was with having the logic in a for loop. Since the size of newbuffer is 256, the program would not exit the for loop unless all of the characters had been entered and newbuffer was full. By taking my logic out of the for loop, the function could complete and return to main to be recalled in the main loop when the next character was entered.
I also added a flag variable so that I can print the string that was entered when the user types the carriage return button.
Receive Callback Routine:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//Prevent unused argument(s) compilation warning
UNUSED(huart);
newbuffer[i] = buffer[0] //put value entered from keyboard into newbuffer array
if (newbuffer[i] == '\r') //if user enters a carriage return the input will be flagged and trigger the while loop to print the string
{
flag = 1;
}
else
{
flag = 0;
}
memset(buffer, 0, sizeof(buffer)); //clear buffer array to receive next keyboard value
i++; //increment newbuffer index
HAL_UART_Receive_IT (&UartHandle, buffer, 1); //call interrupt that handles entering keyboard values
Main:
int main(void)
{
HAL_Init();
/* Configure the system clock to 180 MHz */
SystemClock_Config();
/* Initialize BSP Led for LED2 */
BSP_LED_Init(LED2);
UartHandle.Instance = USARTx;
UartHandle.Init.BaudRate = 9600;
UartHandle.Init.WordLength = UART_WORDLENGTH_9B;
UartHandle.Init.StopBits = UART_STOPBITS_1;
UartHandle.Init.Parity = UART_PARITY_EVEN;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle.Init.Mode = UART_MODE_TX_RX;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&UartHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
NVIC_SetPriority(USART3_IRQn, (1u << __NVIC_PRIO_BITS) - 5u); //set interrupt priority
NVIC_EnableIRQ(USART3_IRQn);
/*INTERRUPT METHOD*/
HAL_UART_Receive_IT (&UartHandle, buffer, 1); //call UART receive interrupt to get keyboard input
//Infinite loop
while (1)
{
//output a message in Hyperterminal requesting keyboard input
printf("\n\rEnter your string: ");
NVIC_DisableIRQ(USART3_IRQn);
if (flag == 1)
{
printf("%s", newbuffer); //string is printed if user enters a carriage return
flag = 0; //reset flag so the interrupt routine can look for another carriage return
memset(newbuffer, 0, sizeof(newbuffer)); //clear newbuffer so it is ready to store a new string
i = 0; //reset index so newbuffer begins storing its new string starting at newbuffer[0]
}
NVIC_EnableIRQ(USART3_IRQn);
HAL_Delay (1000);
}

Related

HAL_FLASHEx_DATAEEPROM_Program hard fault

I use my function to write a string to the eeprom bank of the stm32l073.
Directly after the function HAL_FLASHEx_DATAEEPROM_Program will be called, the sytem goes into HardFault:
Debug Stack
The address i want to write is in the correct space 0x080803b4: MemoryMap
Do you see any problem in that process? I tried also to erase this WORD before write, but same problem with that write function.
HAL_StatusTypeDef eepromDrv_WriteWORD(uint32_t address, const uint32_t* pData, uint16_t dataLength)
{
bool bSuccess = true;
uint32_t ui32Addr = 0;
HAL_StatusTypeDef status = HAL_ERROR;
HAL_FLASHEx_DATAEEPROM_DisableFixedTimeProgram(); // Only Erase befor Write, when EEPROM_READ != DATA
HAL_FLASHEx_DATAEEPROM_Unlock();
for (ui32Addr=0;ui32Addr < dataLength; ui32Addr+=4,pData++)
{
if ((HAL_FLASHEx_DATAEEPROM_Program( FLASH_TYPEPROGRAMDATA_WORD, address + ui32Addr, *pData)) != HAL_OK)
{
bSuccess = false;
}
}
HAL_FLASHEx_DATAEEPROM_Lock();
if(true == bSuccess)
{
status = HAL_OK;
}
return status;
}

Unable to enter into a particular switch case

The first case of switch is to initialize the values, when i enter into the function the switch is not going to case INI_QUEUE, instead its going to CHECK_QUEUE or ENABLE_QUEUE.
below is my code and debug snippet.
can anyone please tell me, what is the problem which is making it not to go to INI_QUEUE
main.c file
int main(void)
{
/* USER CODE BEGIN 1 */
char buffer[2] = { 0 };
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_TIM14_Init();
/* USER CODE BEGIN 2 */
// HAL_TIM_Base_Start_IT(&htim14);
__HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE);
// HAL_UART_Receive_IT(&huart2, (uint8_t*) buffer, 1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// HAL_UART_Receive_IT(&huart2, (uint8_t*) buffer, 1);
fn_cirQ();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
typedef enum{
INI_QUEUE, CHECK_COM, EN_QUEUE, DE_QUEUE, UART_SEND
}Qstate;
void init_queue(queues *q, int max_size){
q->size =max_size;
q->values = malloc(sizeof(int)*q->size);
q->num = 0;
q->front = 0;
q->rare = 0;
}
void fn_cirQ()
{
queues q1;
static Qstate queuestates = INI_QUEUE;
switch (queuestates)
{
case INI_QUEUE:
init_queue(&q1, SIZE);
queuestates = CHECK_COM;
break;
case CHECK_COM:
if(Q_state == 0xFF)
{
queuestates = EN_QUEUE;
}
else if(Q_state == 0x00)
{
queuestates = DE_QUEUE;
}
else if(Q_state != 0x55)
{
HAL_UART_Transmit_IT(&huart2, (uint8_t*) errormsg, 20);
}
break;
case EN_QUEUE:
en_queue(&q1, temp[1]);
Q_state = 0x55;
j = 0;
queuestates = UART_SEND;
break;
case DE_QUEUE:
dequeue(&q1);
Q_state = 0x55;
j=0;
queuestates = UART_SEND;
break;
case UART_SEND:
HAL_UART_Transmit_IT(&huart2, (uint8_t*)&q1, sizeof(q1));
queuestates = CHECK_COM;
break;
}
}
[debug window,queuestates is assigned with CHECK_COM state instead of INI_QUEUE]
The initialization of a static variable is only done once, at program start-up. So the first time the function is called, it will go to the INI_QUEUE case.
From there on, any next time the function is called it will go the queue state set by the previous call.
But the first time it will go to INI_QUEUE.

Working with byte array I get an "invalid conversion from char* to byte"

I am reading and writing to an RFID tag using MFRC522.h
I can currently read the UID of a card and dump it to "UIDChar"
The UID of a card typically is 8 characters.
UID Example: 467EE9A9
I can use the mfrc522.MIFARE_SetUid function to write this UID to a new card. In order to do this I have to set the newUID to:
0x46,0x7E,0xE9,0xA9f
I have written this into my code.
What I am wanting to do is convert the UID string into a byte array so that I can use that in place of my manually written 0x46,0x7E,0xE9,0xA9.
I use the convert function to convert the UID into that format.
It can that be displayed with "buf".
Serial.println(buf);
Now my problem. If I replace the
byte newUid[] = {0x46,0x7E,0xE9,0xA9f};
with
byte newUid[] = {buf};
I get the error
invalid conversion from 'char*' to 'byte {aka unsigned char}'
How can I set my "newUid" as "buf"?
#define SS_PIN 0 //D2
#define RST_PIN 2 //D1
#include <SPI.h>
#include <MFRC522.h>
/* For RFID */
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
char buf[40]; // For string to byte array convertor
void convert(char *s)
{
int i, j, k;
buf[0] = 0x0;
for (j = 0, i = 0, k = 0; j < strlen(s); j++)
{
if (i++ == 0) {
buf[k++] = '0';
buf[k++] = 'x';
}
buf[k++] = s[j];
if (i == 2) {
if(j != strlen(s) -1) buf[k++] = ',';
i = 0;
}
}
buf[k] = 0x0;
}
void clone() {
/* RFID Read */
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent())
{
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial())
{
return;
}
//Show UID on serial monitor
Serial.println();
Serial.print(" UID tag :");
// Very basic UID dump
unsigned int hex_num;
hex_num = mfrc522.uid.uidByte[0] << 24;
hex_num += mfrc522.uid.uidByte[1] << 16;
hex_num += mfrc522.uid.uidByte[2] << 8;
hex_num += mfrc522.uid.uidByte[3];
// Get UID
int NFC_id = (int)hex_num;
Serial.print(NFC_id, HEX);
// Convert UID to string using an int and a base (hexadecimal)
String stringUID = String(NFC_id, HEX);
char UIDChar[10];
stringUID.toCharArray(UIDChar,10);
delay(1000);
Serial.println();
// Convert to uppercase
for (int i = 0; i < strlen(UIDChar); i++ )
{
if ( UIDChar[i] == NULL ) break;
UIDChar[i] = toupper(UIDChar[i]);
}
//Serial.print( &UIDChar[0] );
Serial.println();
convert(UIDChar);
Serial.println(buf);
/* RFID Write */
// Set new UID
// Change your UID hex string to 4 byte array
// I get error if I use byte newUid[] = {buf};
/* ERROR HERE */
byte newUid[] = {0x46,0x7E,0xE9,0xA9};
if ( mfrc522.MIFARE_SetUid(newUid, (byte)4, true) ) {
Serial.println( "Wrote new UID to card." );
}
// Halt PICC and re-select it so DumpToSerial doesn't get confused
mfrc522.PICC_HaltA();
if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) {
return;
}
// Dump the new memory contents
Serial.println( "New UID and contents:" );
mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
}
void setup() {
Serial.begin ( 115200 );
/* RFID */
SPI.begin(); // Initiate SPI bus
mfrc522.PCD_Init(); // Initiate MFRC522
clone();
}
void loop() {
}
When you write
byte newUid[] = {buf};
you are trying to initialise newUid with a single element (there's only one item inside your {}), and that element is buf, which is a char* (or a char[]). That's why you get the error - you are trying to assign an array with one char* to a variable whose elements are bytes.
Without reading your full code in detail, I don't know why you are trying to do this assignment, rather than just use your buf array as it is. But to fix the problem, you probably just want to use
byte* newUid = buf;

Stopping the program when reading data from UART

I have this simple code:
while(1){
char dolar = gps_get_char();//read char from uart
if ((dolar == '$') || (receive_dolar == 1)){
receive_dolar = 1;
gps_get_nmea(nmea_in, sizeof(nmea_in));
rozloz_nmea();
receive_dolar = 0;
}
/*control running program*/
if (tl2 == 1){ //flag button from interrupt
LCD ^= (1 << LED_ON_OFF);
tl2 = 0;
}
}
But when the GPS is turned off, so the program stops here:
char dolar = gps_get_char();//read char from uart
Where function gps_get_char();
char gps_get_char()
{
unsigned int in = 0;
do {
in = uart1_getc();
} while((in & UART_NO_DATA) || (in & UART_BUFFER_OVERFLOW));
return((char) in);
}
Any idea why the program is stopped?
Even if your current approach works, you are prone at losing UART data. You should really be using interrupts instead of polling. Have the interrupt fill a sufficiently large buffer and set a flag condition when it is done. Then, have the program process the buffer.
Cheers.

USART embedded C. trigger character to store array

USART embedded c for atmega328p. trying to store an array of 10 characters of whatever user inputs after a certain character is received(in my case char $). This compiles for me but only outputs dollar signs when I input a string of chars using hercules utility reader. any help appreciated
the following is a copy of the code I am using
#define FOSC 16000000 // Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1
#include <avr/io.h>
//#include <stdio.h>
char trig='$';
char arr[10];
//This function is used to initialize the USART
//at a given UBRR value
void USARTInit(unsigned int ubrr)
{
//Set Baud rate
UBRR0H = (ubrr>>8);
UBRR0L = ubrr;
//Enable The receiver and transmitter
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
// Set fram format: 8data 2stopBit
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
//This function is used to read the available data
//from USART. This function will wait untill data is
//available.
unsigned char USARTReadChar( void )
{
//Wait untill a data is available
while(!(UCSR0A & (1<<RXC0)))
{
//Do nothing
}
//Now USART has got data from host
//and is available is buffer
return UDR0;
}
//This function writes the given "data" to
//the USART which then transmit it via TX line
void USARTWriteChar(unsigned char data)
{
//Wait untill the transmitter is ready
while(!(UCSR0A & (1<<UDRE0)))
{
//Do nothing
PORTD ^= 1 << PINB2;
}
//Now write the data to USART buffer
UDR0 = data;
}
int main(void)
{
DDRB |= 1 << PINB2;
//Varriable Declaration
char data;
USARTInit(MYUBRR);
//Loop forever
while(1)
{
//Read data
data = USARTReadChar();
int i =0;
//if incoming data is a dollar sign(trig),
if(data==trig)
{
//start a loop to collect data from buffer
for(i=0;i<10;i++)
{
//array has 10 elements, will fill up the ith element as per for loop
arr[i]=data;
// printf("arrayoutput %c\n",arr[i]);
USARTWriteChar(data);
}
}
}
}
I edited the while loop as suggested by oleg but still cannot get it to return the array .the entire code is as follows:
#define FOSC 16000000 // Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1
#include <avr/io.h>
#include <stdio.h>
char trig='$';
char arr[10];
//This function is used to initialize the USART
//at a given UBRR value
void USARTInit(unsigned int ubrr)
{
//Set Baud rate
UBRR0H = (ubrr>>8);
UBRR0L = ubrr;
//Enable The receiver and transmitter
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
// Set fram format: 8data 2stopBit
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
//This function is used to read the available data
//from USART. This function will wait untill data is
//available.
unsigned char USARTReadChar( void )
{
//Wait untill a data is available
while(!(UCSR0A & (1<<RXC0)))
{
//Do nothing
}
//Now USART has got data from host
//and is available is buffer
return UDR0;
}
//This function writes the given "data" to
//the USART which then transmit it via TX line
void USARTWriteChar(unsigned char data)
{
//Wait untill the transmitter is ready
while(!(UCSR0A & (1<<UDRE0)))
{
//Do nothing
PORTD ^= 1 << PINB2;
}
//Now write the data to USART buffer
UDR0 = data;
}
int main(void)
{
DDRB |= 1 << PINB2;
//Varriable Declaration
char data;
USARTInit(MYUBRR);
//Loop forever
//Read data
char input[10];
while(1){
data = USARTReadChar();
if(data == trig){
for(int i = 0; i < 10; i++){
//here we're saving 10 characters to input array
input[i] = USARTReadChar();
USARTWriteChar(input[i]);//tested without this also
}
}
}
}
Try to read chars in for() loop:
char input[10];
while(1){
data = USARTReadChar();
if(data == trig){
for(int i = 0; i < 10; i++){
//here we're saving 10 characters to input array
input[i] = USARTReadChar();
}
/* UPD: write stored array to console */
for(int i =0; i < 10; i++){
USARTWriteChar(input[i]);
}
/* those symbols are needed to emulate Enter button */
USARTWriteChar('\r');
USARTWriteChar('\n');
}
}
UPD: this code does exactly that you asked. It stores 10 chars in memory. To return them to console (utility reader) you have to use USARTWriteChar().

Resources