Последовательная связь AVR C: печать номера фиксированных кнопок
Я работаю с микроконтроллером и платой ввода / вывода. Мой код проверяет состояние (ВКЛ / ВЫКЛ) некоторых фиксированных кнопок на плате ввода-вывода и в зависимости от состояния кнопки выполняет побитовую операцию со значением int, поэтому оно представляет число от 0-15 или 0000 до 1111 в двоичный файл.
У меня на плате 4 фиксированные кнопки DS1 - DS4, DS1 - LSB, а DS4 - MSB. Так, например:
DS1 = ON, DS2 = OFF, DS3 = OFF, DS4 = OFF
num = 0001 binary and 1 in decimal
А также
DS1 = ON, DS2 = OFF, DS3 = ON, DS4 = OFF
num = 0101 binary and 5 in decimal
У меня есть функция с именем "printDec", которая принимает значение типа int, находит его размер с точки зрения количества цифр и преобразует его в массив или строку символов, а затем передает их на экран последовательной связи по одному символу за раз.
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <string.h>
#define F_CPU 16000000UL
/*
Input Button
---------------------------------------
Romeo Board : | d2 | d3 | d4 | d5 |
Atmega chip : | pd2 | pd3 | pd4 | pd5 |
I/O Board : | DS1 | DS2 | DS3 | DS4 |
*/
void initUART(unsigned int baud);
void transmitByte(unsigned char data);
unsigned char receiveByte(void);
int getNumOfDigits(int num);
void printDec(int num);
int main(void) {
int num = 0;
int old_num = 0;
DDRD = 0b00000000;
PORTD = 0b00111100;
int hasPrinted = 0;
initUART(9600);
while(1) {
// 1st bit LSB
if((PIND & 0b00000100) == 0) {
num = num | 0b00000001;
} else {
num = num & 0b11111110;
}
// 2nd bit
if((PIND & 0b00001000) == 0) {
num = num | 0b00000010;
} else {
num = num & 0b11111101;
}
// 3rd bit
if((PIND & 0b00010000) == 0) {
num = num | 0b00000100;
} else {
num = num & 0b11111011;
}
//4th bit MSB
if((PIND & 0b00100000) == 0) {
num = num | 0b00001000;
} else {
num = num & 0b11110111;
}
if(num != old_num) {
old_num = num;
printDec(num);
transmitByte('-');
transmitByte('-');
transmitByte('>');
}
/*
Tested printDec without button it seems to work fine
if(hasPrinted == 0) {
printDec(15);
transmitByte(',');
printDec(16);
transmitByte(',');
printDec(21);
transmitByte(',');
printDec(num);
transmitByte(',');
num = num | 0b00001111;
printDec(num);
transmitByte(',');
num = num & 0b00000011;
printDec(num);
transmitByte(',');
hasPrinted = 1;
}
*/
}
return 0;
}
void initUART(unsigned int baud) {
/*
Initialize settings for uart functions.
Must be done once at the beginning of the program.
*/
//Normal mode UBRR formula
unsigned int ubrr = F_CPU/16/baud-1;
//shift MSB and store in UBRR0H
UBRR0H = (unsigned char) (ubrr >> 8);
//store LSB in UBRR0L
UBRR0L = (unsigned char) ubrr;
//Enable transmitter/receiver
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
//8-Bit Characters, 0 Stop bits, No parity
UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);
}
void transmitByte(unsigned char data) {
/*
Write byte to UART
*/
//Wait for empty transmit buffer
while(!(UCSR0A & (1 << UDRE0)));
//Start transmission by writing to UDR0
UDR0 = data;
}
unsigned char receiveByte(void){
/*
Read byte from UART
*/
//Wait for incoming byte
while(!(UCSR0A & (1 << RXC0)));
//Return the byte
return UDR0;
}
int getNumOfDigits(int num) {
int s;
while(num != 0) {
num /= 10;
++s;
}
return s;
}
void printDec(int num) {
unsigned char *str;
int size;
int i;
size = getNumOfDigits(num);
str = (char *) malloc(size+1);
sprintf(str, "%d", num);
for(i = 0; i < size; i++) {
transmitByte(str[i]);
_delay_ms(100);
}
free(str);
}
Когда я пробую этот код с моей замазкой для последовательного соединения, он некоторое время печатает правильное значение, а затем внезапно печатает все эти странные символы вместе со значением, которое я хотел. Я не уверен, почему это работало нормально с нажатыми кнопками, но не с фиксированной кнопкой, и я не понимаю, почему все эти странные символы появляются на экране.
1 ответ
Одна проблема заключается в следующем:
int getNumOfDigits(int num) {
int s;
while (num != 0) { num /= 10; ++s; }
return s;
}
Локальная переменная не инициализируется, поэтому вы получаете мусор.
Тем не менее, код достаточно раздут для передачи числа из 1 или 2 цифр (от 0 до 15), также с учетом контекста (встроенный AVR).
Попробуйте думать о printDec() по-другому:
transmitByte(num / 10 + '0');
transmitByte(num % 10 + '0');
Передает num
в десятичном виде с двумя цифрами (00 ... 15). Сначала он принимает число десятков и, добавляя код ascii для символа '0', преобразует его в нужный код ascii. То же самое для единицы измерения.
Если вы хотите одну цифру для чисел от 0 до 9, напишите это:
if (num >= 10) transmitByte(num / 10 + '0');
transmitByte(num % 10 + '0');
Эта версия printDec() более встроенная:-)