I am working with a microcontoller and a I/O board. My code checks the state (ON/OFF) of some fixed buttons on the I/O board and based on the the state of the button performs bitwise operation to a int value so it represents a number from 0-15 or 0000 to 1111 in binary.
I have 4 fixed button on my board DS1 - DS4, DS1 is LSB while DS4 is MSB. So for example:
DS1 = ON, DS2 = OFF, DS3 = OFF, DS4 = OFF
num = 0001 binary and 1 in decimal
And
DS1 = ON, DS2 = OFF, DS3 = ON, DS4 = OFF
num = 0101 binary and 5 in decimal
I have a function called "printDec" that takes a int value, find its size in terms of number of digits and converts it to a char array or string, then transmit it to serial communication screen one char at a time.
#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);
}
When I try this code with my serial communication putty, it print correct value for some time and then all of the sudden print all these weird symbols along with the value I wanted. I am not sure why this worked fine with pressed down buttons but not with fixed button and I don't understand why all these weird symbols are showing up on the screen.
One problem is this:
int getNumOfDigits(int num) {
int s;
while (num != 0) { num /= 10; ++s; }
return s;
}
The local var s is not initialized so you get garbage.
That said, the code is quite bloated to transmit a number of 1 or 2 digits (from 0 to 15), also considering the context (embedded AVR).
Try to think printDec() in this other way:
transmitByte(num / 10 + '0');
transmitByte(num % 10 + '0');
It transmits num
in decimal with two digits (00 ... 15). First it takes the tens number and, by adding the ascii code for the '0' character, it transforms it in the wanted ascii code. The same then for the unit digit.
If you want a single digit for numbers from 0 to 9, then write this:
if (num >= 10) transmitByte(num / 10 + '0');
transmitByte(num % 10 + '0');
This version of printDec() is more embedded :-)