Последовательная связь 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() более встроенная:-)

Другие вопросы по тегам