I'm simply trying to convert ASCII to Decimal on my microcontroller (in C) before it is sent over bluetooth.
Control + F and find ASCII in this library.
http://ww1.microchip.com/downloads/en/DeviceDoc/MPLAB_C18_Libraries_51297f.pdf
This is the relevant section of my code.
PIR1bits.ADIF=0;
while(x ==1)
{
ConvertADC(); //ADCONbits.GO/DONE=1 , Starts the A/D conversion process.
while(BusyADC()){} // Wait for completion
Delay10KTCYx(0);
Delay10KTCYx(0);
Delay10KTCYx(0);
Delay10KTCYx(0);
while(BusyUSART());
putcUSART(ADRESH); //prints or places the character into bluetooth
while(BusyUSART());
putcUSART(ADRESL); //prints or places the character into bluetooth
PIR1bits.ADIF=0;
}
//CloseADC(); // Disable A/D converter
}
What I have tried.
1) atob(ADRESH) atob(ADRESL)
2) atof(ADRESH) atof(ADRESL)
3) atoi(ADRESH) atoi(ADRESL)
4) atol(ADRESH) atol(ADRESL)
5) putCUSART (atob/f/i/l(ADRESH)) putCUSART(atob/f/i/l(ADRESL)
This is my Full code
/*********************************************************************
*
* Example User Program to be used with resident Bootloader
*
*********************************************************************
* FileName: main.c
* File Version: 2.0, 15-February
* Dependencies: See INCLUDES section below
* Processor: PIC18
* Compiler: C18 2.30.01+
* Company: emxys Ltd.
*
*
*
* Copyright: 2009 emxys Ltd. ALL RIGHTS RESERVED
*
* Notes: This is a basic template for PIC18F4550 running
* uIceBlue module.
*
********************************************************************/
#define PROGRAMMABLE_WITH_USB_HID_BOOTLOADER
/** INCLUDES *******************************************************/
#include <p18cxxx.h>
#include <portb.h>
#include <usart.h>
#include <delays.h>
#include <adc.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/** CONFIGURATION **************************************************/
/** V A R I A B L E S **********************************************/
#pragma idata
int i=0; //number of characters of command
int x=1;
int y=1;
/** PRIVATE PROTOTYPES *********************************************/
void YourHighPriorityISRCode();
void YourLowPriorityISRCode();
/** VECTOR REMAPPING ***********************************************/
#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)
#define REMAPPED_RESET_VECTOR_ADDRESS 0x1000
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x1008
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x1018
#endif
#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)
extern void _startup (void); // See c018i.c in your C18 compiler dir
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
void _reset (void)
{
_asm goto _startup _endasm
}
#endif
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS
void Remapped_High_ISR (void)
{
_asm goto YourHighPriorityISRCode _endasm
}
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS
void Remapped_Low_ISR (void)
{
_asm goto YourLowPriorityISRCode _endasm
}
#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)
//Note: If this project is built while one of the bootloaders has
//been defined, but then the output hex file is not programmed with
//the bootloader, addresses 0x08 and 0x18 would end up programmed with 0xFFFF.
//As a result, if an actual interrupt was enabled and occured, the PC would jump
//to 0x08 (or 0x18) and would begin executing "0xFFFF" (unprogrammed space). This
//executes as nop instructions, but the PC would eventually reach the REMAPPED_RESET_VECTOR_ADDRESS
//(0x1000 or 0x800, depending upon bootloader), and would execute the "goto _startup". This
//would effective reset the application.
//To fix this situation, we should always deliberately place a
//"goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS" at address 0x08, and a
//"goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS" at address 0x18. When the output
//hex file of this project is programmed with the bootloader, these sections do not
//get bootloaded (as they overlap the bootloader space). If the output hex file is not
//programmed using the bootloader, then the below goto instructions do get programmed,
//and the hex file still works like normal. The below section is only required to fix this
//scenario.
#pragma code HIGH_INTERRUPT_VECTOR = 0x08
void High_ISR (void)
{
_asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
}
#pragma code LOW_INTERRUPT_VECTOR = 0x18
void Low_ISR (void)
{
_asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
}
#endif //end of "#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)||defined(PROGRAMMABLE_WITH_USB_LEGACY_CUSTOM_CLASS_BOOTLOADER)"
#pragma code
//These are your actual interrupt handling routines.
#pragma interrupt YourHighPriorityISRCode
void YourHighPriorityISRCode()
{
unsigned char buffer[40];
if (PIR1bits.RCIF == 1) //USART Interruption
{
buffer[i]= getcUSART(); //characters of the commands.
if (buffer[i]=='\n')
buffer[i]='\r';
if (i<4 & buffer[i]=='\r')
{
RCREG=0; // clear buffer
TXREG=0;
i=0;
PIR1bits.RCIF =0;
_asm RETFIE 0x0 _endasm
}
else if (i==4 & buffer[4]=='\r')
{
/** PORTD commands *************************************************************/
//COMMAND: 0xhi or 0xHI : set bit x from PORTD
if ((buffer [0] == '0' & buffer[2] == 'h' & buffer[3]== 'i') || (buffer[0] == '0' & buffer[2] == 'H' & buffer[3]== 'I'))
{
switch (buffer[1])
{
case '0':
PORTDbits.RD0 = 1;
break;
case '1':
PORTDbits.RD1 = 1;
break;
case '2':
PORTDbits.RD2 = 1;
break;
case '3':
PORTDbits.RD3 = 1;
break;
case '4':
PORTDbits.RD4 = 1;
break;
case '5':
PORTDbits.RD5 = 1;
break;
case '6':
PORTDbits.RD6 = 1;
break;
case '7':
PORTDbits.RD7 = 1;
break;
}
putcUSART('#');
WriteUSART(buffer[1]);
putrsUSART("HI");
}
//COMMAND: 0xlo or 0xLO : clear bit x from PORTD
if ((buffer[0] == '0' & buffer[2] == 'l' & buffer[3]== 'o') || (buffer [0] == '0' & buffer[2] == 'L' & buffer[3]== 'O'))
{
switch (buffer[1])
{
case '0':
PORTDbits.RD0 = 0;
break;
case '1':
PORTDbits.RD1 = 0;
break;
case '2':
PORTDbits.RD2 = 0;
break;
case '3':
PORTDbits.RD3 = 0;
break;
case '4':
PORTDbits.RD4 = 0;
break;
case '5':
PORTDbits.RD5 = 0;
break;
case '6':
PORTDbits.RD6 = 0;
break;
case '7':
PORTDbits.RD7 = 0;
break;
}
putcUSART('#');
WriteUSART(buffer[1]);
putrsUSART("LO");
}
//COMMAND: aclr or ACLR : clear PORTD
if ((buffer[0] == 'a' & buffer[1] == 'c' & buffer[2]== 'l' & buffer[3] == 'r') || ( buffer[0] == 'A' & buffer[1] == 'C' & buffer[2]== 'L' & buffer[3] == 'R'))
{
PORTD= 0x00;
}
//COMMAND: aset or ASET : set PORTD
if ((buffer[0] == 'a' & buffer[1] == 's' & buffer[2]== 'e' & buffer[3] == 't') || ( buffer[0] == 'A' & buffer[1] == 'S' & buffer[2]== 'E' & buffer[3] == 'T'))
{
PORTD= 0xFF;
}
//COMMAND: dqst or DQST : query state of PORTD
if ((buffer[0] == 'd' & buffer[1] == 'q' & buffer[2]== 's' & buffer[3] == 't') || ( buffer[0] == 'D' & buffer[1] == 'Q' & buffer[2]== 'S' & buffer[3] == 'T'))
{
putcUSART('#');
WriteUSART(PORTD);
}
//COMMAND: dldx or DLDx : load the value x on PORTD
if ((buffer[0] == 'd' & buffer[1]== 'l' & buffer[2] == 'd') || ( buffer[0] == 'D' & buffer[1]== 'L' & buffer[2] == 'D'))
{
PORTD= buffer[3];
}
/** PORTB commands *************************************************************/
//COMMAND: bqst or BQST : query state of PORTB
if ((buffer[0] == 'b' & buffer[1] == 'q' & buffer[2]== 's' & buffer[3] == 't') || ( buffer[0] == 'B' & buffer[1] == 'Q' & buffer[2]== 'S' & buffer[3] == 'T'))
{
putcUSART('#');
WriteUSART(PORTB);
}
//COMMAND: 0xst or 0xST : show the state of bit x from PORTB
if ((buffer[0] == '0' & buffer[2]== 's' & buffer[3] == 't') || ( buffer[0] == '0' & buffer[2]== 'S' & buffer[3] == 'T'))
{
unsigned status;
switch (buffer[1])
{
case '0':
status = PORTBbits.RB0;
break;
case '1':
status = PORTBbits.RB1;
break;
case '2':
status = PORTBbits.RB2;
break;
case '3':
status = PORTBbits.RB3;
break;
case '4':
status = PORTBbits.RB4;
break;
case '5':
status = PORTBbits.RB5;
break;
case '6':
status = PORTBbits.RB6;
break;
case '7':
status = PORTBbits.RB7;
break;
}
putcUSART('#');
WriteUSART(buffer[1]);
if (status)
putrsUSART("HI");
else
putrsUSART("LO");
}
/** AD converter commands *************************************************************/
//COMMAND: 0xad or 0xAD : x will be the input for the AD converter
if ((buffer[0] == '0' & buffer[2]== 'a' & buffer[3] == 'd') || ( buffer[0] == '0' & buffer[2]== 'A' & buffer[3] == 'D'))
{
switch (buffer[1])
{
case '0':
SetChanADC( ADC_CH0 );
break;
case '1':
SetChanADC( ADC_CH1 );
break;
case '2':
SetChanADC( ADC_CH2 );
break;
case '3':
SetChanADC( ADC_CH3 );
break;
case '4':
SetChanADC( ADC_CH4 );
break;
case '5':
SetChanADC( ADC_CH5 );
break;
case '6':
SetChanADC( ADC_CH6 );
break;
case '7':
SetChanADC( ADC_CH7 );
break;
}
PIR1bits.ADIF=0;
while(x ==1)
{
ConvertADC();
//ADCONbits.GO/DONE=1 , Starts the A/D conversion process.
while(BusyADC())
{} // Wait for completion
//putcUSART('\n');
Delay10KTCYx(0);
Delay10KTCYx(0);
Delay10KTCYx(0);
Delay10KTCYx(0);
while(BusyUSART());
putcUSART(ADRESH);
while(BusyUSART());
putcUSART(ADRESL);
PIR1bits.ADIF=0;
}
//CloseADC(); // Disable A/D converter
}
i=-1;
PIR1bits.RCIF =0;
}
else if (i>4 & buffer[i]=='\r')
{
RCREG=0; //Clear the buffer
TXREG=0;
i=0;
PIR1bits.RCIF =0;
_asm RETFIE 0x0 _endasm
}
i++;
}
} //This return will be a "retfie fast", since this is in a #pragma interrupt section
#pragma interruptlow YourLowPriorityISRCode
void YourLowPriorityISRCode()
{
//Check which interrupt flag caused the interrupt.
//Service the interrupt
//Clear the interrupt flag
//Etc.
} //This return will be a "retfie", since this is in a #pragma interruptlow section
/** DECLARATIONS ***************************************************/
#pragma code
/******************************************************************************
* Function: void main(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Main program entry point.
*
* Note: None
*****************************************************************************/
void main(void)
{
//Configure Ports : 1 is input, 0 is output
TRISA=1;
TRISB=1;
PORTB=0;
TRISD=0;
PORTD=0;
TRISE=1;
//Configure Interruptions
INTCONbits.GIE=1; // Global Interruption Enable bit
INTCONbits.PEIE=1; // Peripheral Interruption Enable bit
//PIE1bits.TXIE=1; // EUSART Transmit Interruption Enable bit
PIE1bits.RCIE=1; // EUSART Receive Interruption Enable bit
IPR1bits.RCIP=1; // EUSART Receive Interruption Priority bit
//Configure USART
//configure RC6/TX/CK and RC7/RX/DT/SDO as an EUSART
TRISCbits.TRISC6=1;
TRISCbits.TRISC7=1;
RCSTAbits.SPEN=1; //Serial Port Enable bit
BAUDCONbits.BRG16=0;//16-Bit Baud Rate Register Enable bit
/* EUSART BAUD RATE CONFIGURATION ***********************************
;OpenUSART(...,SPBRG) configure the USART
;
; SPBRG value => 312 # 9600 bauds
; 155 # 19200 bauds
; 77 # 38400 bauds
; 51 # 57600 bauds
; 25 # 115200 bauds
; 12 # 230400 bauds
; 6 # 460800 bauds
; 2 # 921600 bauds
;
; Check the MPLAB C18 Libraries and the 18F4550 datasheet for more
; information
********************************************************************/
OpenUSART(USART_TX_INT_OFF & //Interruption on Transmission
USART_RX_INT_ON & //Interruption on Receipt
USART_ASYNCH_MODE & //USART Mode
USART_EIGHT_BIT & //Transmission Width
USART_CONT_RX & //Reception mode
USART_BRGH_HIGH, 155); //High Baud Rate Select bit, Baud rate at which the USART operates
//Configure AD converter
ADCON0bits.ADON=1; //Enable AD converter
/* AD converter configuration *******************************************
;OpenADC(...,portconfig) configure the AD converter
;
; portconfig value => A/D Port Configuration Control bits in decimal
;
; The channel for the A/D conversion is selected by a command
;
; Default Vref+ = Vdd, default Vref- = Vss
;
; Check the MPLAB C18 Libraries and the 18F4550 datasheet for more
; information
************************************************************************/
OpenADC( ADC_FOSC_64 & //clock source
ADC_RIGHT_JUST & //result justification
ADC_20_TAD, //acquisition time selected must be TAD>0,7us.
ADC_INT_OFF & //interruptions off
ADC_VREFPLUS_VDD & //Voltage reference
ADC_VREFMINUS_VSS, 7 ); //Port configuration is any value from 0 to 15 inclusive
while(1)
{
//INSERT YOUR MAIN CODE HERE
}
}//end main
/** EOF main.c *************************************************************/
ADRESH and ADRESL are both 8-bit byte variables. They need to be converted to an ASCII string.
atob() / atof() / atoi() / atol() convert an ASCII string to a byte/float/integer/long value. You pass them a string and they return a number.
char atob(const char * s); // convert string to 8-bit signed character
double atof(const char * s); // convert string to floating point value
int atoi(const char * s); // convert string to 16-bit signed integer
long atol(const char * s); // convert string to long integer representation
You want to use the btoa() / itoa() / ltoa() (byte/integer/long to ASCII) functions. You pass them the value to convert along with a character buffer for storing the string. They return the string representation of the passed value.
char * btoa(char value, char * string); // convert byte value to string
char * itoa( int value, char * string); // convert integer value to string
char * ltoa(long value, char * string); // convert long value to string
In your case, you'll want to use btoa() (or itoa() if you combine ADRESH and ADRESL) and putsUSART().
char string[5];
while(BusyUSART());
putsUSART(btoa(ADRESH, string)); // prints high byte to bluetooth
while(BusyUSART());
putsUSART(btoa(ADRESL, string)); // prints low byte to bluetooth
or
char string[7];
unsigned int value = (unsigned int) ADRESH * 256 + ADRESL; // reassemble reading
while(BusyUSART());
putsUSART(itoa(value, string)); // prints ADC reading to bluetooth
Since you are using the string library (#include <string.h>), another option is to print a formatted output to a string using (sprintf()). The code would now be:
char string[9];
sprintf(string, "%d %d", ADRESH, ADRESL); // convert values to string
while(BusyUSART());
putsUSART(string); // prints ADC readings to bluetooth
or
char string[7];
unsigned int value = (unsigned int) ADRESH * 256 + ADRESL; // reassemble reading
sprintf(string, "%d", value); // convert value to string
while(BusyUSART());
putsUSART(string); // prints ADC reading to bluetooth
Related
void set_binuid(uint8_t byte, uint8_t i) {
binuid[(i*4)] = (byte >> 3) & 0x01;
binuid[(i*4)+1] = (byte >> 2) & 0x01;
binuid[(i*4)+2] = (byte >> 1) & 0x01;
binuid[(i*4)+3] = (byte >> 0) & 0x01;
}
void hex_to_bin(void) {
uint8_t i;
for(i = 0; i < 8; i++) {
if (wieganduid[i] >= '0' && wieganduid[i] <= '9') {
/* Numerical representation */
set_binuid(wieganduid[i] - '0', i);
} else {
/* Number represented by a letter */
switch(wieganduid[i]) {
case 'A':
set_binuid(0x0A, i);
break;
case 'B':
set_binuid(0x0B, i);
break;
case 'C':
set_binuid(0x0C, i);
break;
case 'D':
set_binuid(0x0D, i);
break;
case 'E':
set_binuid(0x0E, i);
break;
case 'F':
set_binuid(0x0F, i);
break;
}
}
}
}
I am passing the value in these to functions to make binary array out of them, it workes fine as long as uint8_t contained only one hex number or it still works when the value taken in ascii table matches 1-f, but when I get values like already mentioned EF - which converts to ascii i there is obviously no case for i, so Im need to take the EF and move it in another uint8_t with different hex value that would be EF in ascii for the function to work and give me bytes of binary 4 for E and 4 for F.
I'm new to embedded systems and C programming. I am currently trying to program a PCB using an STM32 microcontroller to control an array of 8 fans upon receipt of a single commenad. i.e 00001011 will switch on fans 5, 7 and 8. There are a total of 256 possible combinations and it wouldn't be very efficient to program each individual one.
I am thinking of using an array to achieve this using something like;
fan_array[8] = {fan1, fan2, fan3, fan4, fan5, fan6, fan7, fan8};
printf ("Input fan state"); // user would input binary number as shown above
scanf (%d, fan_array);
Would this set the GPIO pins controlling each fan high or low according to the binary values input into the array?
If you think about it, there are 256 possible combinations, but you're only interested in 8 fans, so all that you need to check is 8 bits:
#include <stdio.h>
#define STATE_ON 0x01
#define STATE_OFF 0x00
void enable_relay(unsigned char relay, unsigned char state)
{
/* This is a brute force approach that enables any relay/port combination:
* relay 8: PB2
* relay 7: PB4
* (...)
* relay 1: PA1
*/
switch(relay)
{
case 8:
if(state == STATE_ON)
GPIOB->ODR |= 0x0004;
else
GPIOB->ODR &= ~0x0004;
break;
case 7:
if(state == STATE_ON)
GPIOB->ODR |= 0x0010;
else
GPIOB->ODR &= ~0x0010;
break;
case 1:
if(state == STATE_ON)
GPIOA->ODR |= 0x0002;
else
GPIOA->ODR &= ~0x0002;
break;
}
}
void check_relay(unsigned char fan_map)
{
int i;
unsigned char bit;
unsigned char state;
for(i=0; i < 8; i++) {
bit = (fan_map&(0x01<<i));
state = ((bit != 0)? STATE_ON : STATE_OFF);
enable_relay( (8-i), state);
}
}
int main(void)
{
unsigned char fan_map = 0x0B; /* 0x0B = 00001011 */
check_relay(fan_map);
}
You need the 8-i part as your bit order is in reverse (fan1 as the leftmost bit) with the value order (MSB is the leftmost bit).
I'm learning embedded programming, and have a LED board and button board hooked up to the same PORT.
The commented out if statement under the chk_button function, certain buttons when activated will add to the num variable its intended increment + 1. IE: pushing button 1 will increment num by three. The current case statement works to spec.
I understand case statements when compiled effectively become look up tables, and thus have smaller footprint and run faster,but I am uncertain as to WHY im getting the bug that I am.
I'm also open to any other criticisms in my code.
// HARDWARE SETUP:
// PORTA is connected to the segments of the LED display. and to the pushbuttons.
// PORTA.0 corresponds to segment a, PORTA.1 corresponds to segement b, etc.
// PORTB bits 4-6 go to a,b,c inputs of the 74HC138.
// PORTB bit 7 goes to the PWM transistor base.
#include <avr/io.h>
#include <util/delay.h>
#define F_CPU 16000000
#define DIGIT_ONE 0x00
#define DIGIT_TWO 0x10
#define DIGIT_COLON 0x20
#define DIGIT_THREE 0x30
#define DIGIT_FOUR 0x40
//******************************************************************************
// debounce_switches
//Checks the state of the button number passed to it. It shifts in ones till
//the button is pushed. Function returns a 1 only once per debounced button
//push so a debounce and toggle function can be implemented at the same time.
//Adapted to check all buttons from Ganssel's "Guide to Debouncing"
//Expects active low pushbuttons on PINA port. Debounce time is determined by
//external loop delay times 12.
//Saves status of button (i) into a state array.
//******************************************************************************
int8_t debounce_switches(uint16_t *state, uint8_t i) {
state[i] = (state[i] << 1) | (! bit_is_clear(PINA, i)) | 0xE000;
if (state[i] == 0xF000) return 1;
return 0;
}
//******************************************************************************
// chk_buttons
//Checks the buttons. Calls debounce_switches in a loop passing both the state array
//and the current switch being checked.
//If debounce_switches returns a 1 for a switch, case statements determine which switch
//was activated, and increments count by the appropriate value.
//******************************************************************************
void chk_buttons(uint16_t *state, uint16_t *num)
{
uint8_t itr;
for( itr=0; itr<8; itr++)
{
if( debounce_switches(state, itr))
{
switch(itr)
{
case 0:
*num += 1;
break;
case 1:
*num += 2;
break;
case 2:
*num += 4;
break;
case 3:
*num += 8;
break;
case 4:
*num += 16;
break;
case 5:
*num += 32;
break;
case 6:
*num += 64;
break;
case 7:
*num +=128;
break;
}
/*
if (itr == 0) *num += 1;
else if(itr == 1) *num += 2;
else if(itr == 2) *num += 4;
else if(itr == 3) *num += 8;
else if(itr == 4) *num += 16;
else if(itr == 5) *num += 32;
else if(itr == 6) *num += 64;
else if(itr == 7) *num += 128;
*/
}
}
}
//******************************************************************************
// itoseven
// Accepts a number from 0 -9 Returns a hex value to display on the seven segment..
//******************************************************************************
uint8_t itoseven(uint8_t num)
{
uint8_t segnum;
switch(num)
{
case 0:
segnum = ~0x3F;
return segnum;
case 1:
segnum = ~0x06;
return segnum;
case 2:
segnum = ~0x5B;
return segnum;
case 3:
segnum = ~0x4F;
return segnum;
case 4:
segnum = ~0x66;
return segnum;
case 5:
segnum = ~0x6D;
return segnum;
case 6:
segnum = ~0x7D;
return segnum;
case 7:
segnum = ~0x07;
return segnum;
case 8:
segnum = ~0x7F;
return segnum;
case 9:
segnum = ~0x6F;
return segnum;
}
}
//***********************************************************************************
// segment_sum
//takes a 16-bit binary input value and displays the result to the LED board.
//***********************************************************************************
void segsum(uint16_t num) {
uint8_t ones;
uint8_t tens;
uint8_t hundreds;
uint8_t thousands;
//break up decimal sum into 4 digit-segments
ones = num % 10;
tens = (num/10)%10;
hundreds = (num/100)%10;
thousands = (num/1000)%10;
//determine how many digits there are
if(num < 10)
{
PORTB = DIGIT_ONE;
PORTA = itoseven(num);
}
else if(num > 9 && num <100)
{
PORTB = DIGIT_ONE;
PORTA = itoseven(ones);
_delay_ms(2);
PORTB = DIGIT_TWO;
PORTA = itoseven(tens);
}
else if(num > 99 && num < 1000)
{
PORTB = DIGIT_ONE;
PORTA = itoseven(ones);
_delay_ms(2);
PORTB = DIGIT_TWO;
PORTA = itoseven(tens);
_delay_ms(2);
PORTB = DIGIT_THREE;
PORTA = itoseven(hundreds);
}
else if (num >999)
{
PORTB = DIGIT_ONE;
PORTA = itoseven(ones);
_delay_ms(2);
PORTB = DIGIT_TWO;
PORTA = itoseven(tens);
_delay_ms(2);
PORTB = DIGIT_THREE;
PORTA = itoseven(hundreds);
_delay_ms(2);
PORTB = DIGIT_FOUR;
PORTA = itoseven(thousands);
}
}
uint8_t main()
{
DDRB = 0xF0; //set port bits 4-7 B as outputs
uint16_t num = 0;
uint16_t state[8];
//initialize array values for debouncing
for(int i=0; i<8; i++)
{
state[i]= 0;
}
while(1)
{
//make PORTA an input port with pullups
DDRA = 0x00;
PORTA = 0xFF;
//enable tristate buffer for pushbutton switches
PORTB = 0x70;
//check the buttons. Increment by appropriate value if switch is active.
chk_buttons(&state, &num);
//rollover at 1023
if(num > 1023)
num = 1;
//switch PORTA to output
DDRA = 0xFF;
//Send num to display
segsum(num);
_delay_ms(2);
}
return 0;
}
I've update these functions to remove the switches as they are not needed at all. Note how the first uses an algorithm in place of a switch and the second uses a table that is easy to adjust in the future. Also, assert/error check your inputs and you'll be a happier camper when things go sideways.
void chk_buttons(uint16_t *state, uint16_t *num)
{
// Assert bad state and num here.
uint8_t itr;
for( itr=0; itr<8; itr++)
{
if( debounce_switches(state, itr))
{
*num += 1 << itr; // Could also use |= as that is what we are doing.
}
}
}
uint8_t itoseven(uint8_t num)
{
// assert num <= 9
const uint8_t kLookup[10] =
{~0x3f, ~0x06, ~0x5B, ~0x4F, ~0x66,
~0x6D, ~0x7D, ~0x07, ~0x7F, ~0x6F};
return kLookup[num];
}
For the last function, if you start at the 4-digit number check and work backwards to the single digit, it becomes a very simple loop to do your complex digit calculation. Just divide your mask from 10,000 to 10. I'll post that code a bit later as I have time.
Update
Here is something I coded up that demonstrates the idea. You will need to modify it for your own functions as right now it just outputs ASCII. It fails for negative numbers (as does your code), but that is very easy to add with a simple if check / ABS / prepend a minus character.
int main(void)
{
int num = 9876;
// Starting at the 5th digit. You could use 1000 instead if
// there were only 4 digits or less ever.
int digitMask = 10000;
char output[16];
int index = 0;
// Handle 0 case.
if(num== 0)
{
output[index++] = '0';
}
else
{
// Skip leading 0's
while((num / digitMask) == 0)
{
digitMask /= 10;
}
// While there may be digits to process...
while(digitMask)
{
// Grab MS Digit and mod it away from total.
int digit = num / digitMask;
num %= digitMask;
// Convert to ASCII (you would use your own function)
output[index++] = digit + '0';
// Update mask - note we could use a for/loop here just as easily.
digitMask /= 10;
}
}
// Terminate string and print it.
output[index] = 0;
printf("%s", output);
return 0;
}
I am trying to display my input at microcontroller ATmega16 to 7 segment displays.
I have found the following code on http://www.avr-tutorials.com/projects/atmega16-based-digital-clock but when I implimented it, it is not working. I am getting a fluctuating output i.e I am not able to control the output at particular pins.
I have two inputs temp1 and temp2, and I want to display each of them on three 7-segment displays. Also, I have not used Pins 2 & 3 as they are interrupt pins and I have used them somewhere else. Pin0,1,4,5,6,7 are used.
The code works fine when some delay is added, otherwise output is generated at random pins.
i.e. The output which I was suppose to display from PIND1 is displayed on all pins,
My code:
#include <avr/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define SegDataPort PORTC
#define SegDataPin PINC
#define SegDataDDR DDRC
#define SegCntrlPort PORTD
#define SegCntrlPin PIND
#define SegCntrlDDR DDRD
/*
* Function Description:
* Encode a Decimal Digit 0-9 to its Seven Segment Equivalent.
*
* Function Arguments:
* digit - Decimal Digit to be Encoded
* common - Common Anode (0), Common Cathode(1)
* SegVal - Encoded Seven Segment Value
*
* Connections:
* Encoded SegVal is return in the other G-F-E-D-C-B-A that is A is the least
* significant bit (bit 0) and G bit 6.
*/
unsigned char DigitTo7SegEncoder(int digit, unsigned char common)
{
unsigned char SegVal;
switch(digit)
{
case 0: if(common == 1) SegVal = 0b00111111;
else SegVal = ~0b00111111;
break;
case 1: if(common == 1) SegVal = 0b00000110;
else SegVal = ~0b00000110;
break;
case 2: if(common == 1) SegVal = 0b01011011;
else SegVal = ~0b01011011;
break;
case 3: if(common == 1) SegVal = 0b01001111;
else SegVal = ~0b01001111;
break;
case 4: if(common == 1) SegVal = 0b01100110;
else SegVal = ~0b01100110;
break;
case 5: if(common == 1) SegVal = 0b01101101;
else SegVal = ~0b01101101;
break;
case 6: if(common == 1) SegVal = 0b01111101;
else SegVal = ~0b01111101;
break;
case 7: if(common == 1) SegVal = 0b00000111;
else SegVal = ~0b00000111;
break;
case 8: if(common == 1) SegVal = 0b01111111;
else SegVal = ~0b01111111;
break;
case 9: if(common == 1) SegVal = 0b01101111;
else SegVal = ~0b01101111;
}
return SegVal;
}
int main(void)
{
int temp1,temp2;
//Suppose my input is 105 and 210, i.e. temp1=105 and temp2=210;
// it contains other information also, not required here
SegDataDDR = 0xFF;
SegCntrlDDR = 0xF3;
SegCntrlPort = 0xF3;
SegDataPort = 0x00;
while(1){
SegDataPort = DigitTo7SegEncoder(temp1%10,1);
SegCntrlPort = ~0x01;
SegDataPort = DigitTo7SegEncoder((temp1/10)%10,1);
SegCntrlPort = ~0x02;
SegDataPort = DigitTo7SegEncoder(temp1/100,1);
SegCntrlPort = ~0x10;
SegDataPort = DigitTo7SegEncoder(temp2%10,1);
SegCntrlPort = ~0x20;
SegDataPort = DigitTo7SegEncoder((temp2/10)%10,1);
SegCntrlPort = ~0x40;
SegDataPort = DigitTo7SegEncoder(temp2/100,1);
SegCntrlPort = ~0x80;
}}
You don't set the DDRs to output anywhere. The pins you want to use as outputs must have the corresponding bit in DDRx set to 1. Otherwise it remains an input pin.
An input pin will show an output, but with a lower current and a more slowly rising edge. Drawing on that current with an LCD may cause the voltage to drop.
Provided that these 7-segment components don't contain any sequential logic inside this is what actually happens:
SegDataPort = DigitTo7SegEncoder(temp1%10,1); // You write the data
SegCntrlPort = ~0x01; // You enable the first 7-segment component
// Then without any delay...
SegDataPort = DigitTo7SegEncoder((temp1/10)%10,1); // You write other data
SegCntrlPort = ~0x02; // You enable the second component
// The without any delay...
So actually the 7-segment component displays previous and next digits at once for a short time.
What about this? (just a pseudocode)
SegCntrlPort = 0xFF; // hide everything
SetDataPort = ... value1 ...;
SegCntrlPort = ~0x01; // show it
WaitForAWhile();
SegCntrlPort = 0xFF; // hide everything to avoid unwanted transitions
SetDataPort = ... value2 ...;
SegCntrlPort = ~0x02; // show it
WaitForAWhile();
And so on.
My project involves sending commands from PuTTY to a Dragon12-Plus2 development board(CodeWarrior 5.1) via an XBEE Wifi. I am using 4 commands to control the leds on the Dragon board {led_enable(), leds_on(integer in hex or decimal here), leds_off(), and led_disable()} from the LBE_DRAGON12_Plus project from LBEbooks.com. Here is my code:
// Final Project: Control leds via XBEE Wifi
#include <hidef.h> /* common defines and macros */
#include <mc9s12dg256.h> /* derivative information */
#include "queue.h"
#pragma LINK_INFO DERIVATIVE "mc9s12dg256b"
#include "main_asm.h" /* interface to the assembly module */
void main(void){
int x,y,z,parser;
int cmdLen = 0;
char c,d,e;
char cbuff[20];
PLL_init(); // set system clock frequency to 24 MHz
lcd_init(); // enable lcd
SCI1_init(9600); // initialize SCI1 at 9600 baud
SCI0_init(9600); // initialize SCI0 at 9600 baud
seg7_disable(); // disable 7 segment display
led_enable(); // enable 8 leds
while(1){
if(SCI1SR1_RDRF == 1){
c = inchar1();
cbuff[cmdLen] = c;
outchar0(cbuff[cmdLen]);
if(c == ';'){
if((cbuff[0] == 'l') && (cbuff[10] == ';')){
leds_off();
cmdLen = 0;
}
else if((cbuff[0] == 'l') && (cbuff[12] == ';')){
led_enable();
cmdLen = 0;
}
else if((cbuff[0] == 'l') && (cbuff[4] == 'd')){
led_disable();
cmdLen = 0;
}
else if((cbuff[0] == 'l') && (cbuff[13] == ';')){
d = cbuff[10];
e = cbuff[11];
switch(d){ // change first number to integer
case('0'):
x = 0x00;
break;
case('1'):
x = 0x10;
break;
case('2'):
x = 0x20;
break;
case('3'):
x = 0x30;
break;
case('4'):
x = 0x40;
break;
case('5'):
x = 0x50;
break;
case('6'):
x = 0x60;
break;
case('7'):
x = 0x70;
break;
case('8'):
x = 0x80;
break;
case('9'):
x = 0x90;
break;
case('a'):
x = 0xa0;
break;
case('b'):
x = 0xb0;
break;
case('c'):
x = 0xc0;
break;
case('d'):
x = 0xd0;
break;
case('e'):
x = 0xe0;
break;
case('f'):
x = 0xf0;
break;
default:
break;
}
switch(e){ // change second number to integer
case('0'):
y = 0x00;
break;
case('1'):
y = 0x01;
break;
case('2'):
y = 0x02;
break;
case('3'):
y = 0x03;
break;
case('4'):
y = 0x04;
break;
case('5'):
y = 0x05;
break;
case('6'):
y = 0x06;
break;
case('7'):
y = 0x07;
break;
case('8'):
y = 0x08;
break;
case('9'):
y = 0x09;
break;
case('a'):
y = 0x0a;
break;
case('b'):
y = 0x0b;
break;
case('c'):
y = 0x0c;
break;
case('d'):
y = 0x0d;
break;
case('e'):
y = 0x0e;
break;
case('f'):
y = 0x0f;
break;
default:
break;
}
z = (x + y); // add integers together
leds_on(z); // display hex number on leds
cmdLen = 0; // reset parser
}
for(parser = 0; parser < 20; parser++){
cbuff[parser] = '\0';
}
}
cmdLen++;
}
}
}
The first command i send works as expected (for instance if i type leds_on(0xaa); in PuTTY the 4 corresponding leds light up), but any command I send after does nothing. I am not sure how to properly reset cbuff so that it operates the same way each time, not just the first time.
EDITED TO SHOW SUGGESTED CHANGES!
If you want to clear all of the elements in the array, then memset would be a wise choice:
memset(cbuff, 0, 20);
That being said, I would strongly agree with #John Bollinger that separating the input and the interpretation functionality would be wise.
However, depending on the application memset might be overkill. A simple cleared array may also be achieved by simply setting the elements of the array to null character ('\0'). Simply call cbuff[0] = '\0' for each element in the array.
What an odd parser. I'd suggest you separate your input stage from your command interpretation stage. That is, read and count characters until you receive a semicolon (;) command terminator, and only then try to interpret the command.
Reset the parser variable (which would more accurately be named something like command_length) only after each attempt to interpret the command, whether successful or not, or if the buffer is about to overflow.