This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

scanf behaviour

I am new to C programming. I wrote calculator program to check my ability in c. I am using ADUC831 demo board, 5x5 matrix keypad, 16x2 LCD in 4 bit mode. following is the code listing. program when run, executes printf statement to show "num1" (checked this by inserting delay) but do not executes scanf to receive float number fl1 and proceeds to display "operator>" and receives variable "operator". on further execution it displays num2> on LCD but skips execution of scanf to receive float no fl2 and directly shows result float no fr. Pl. indicate where am I wrong? Is there a better way to scan keyboard then the one I adopted?
Thanks

listing getkey.c
char _getkey (void)
{
while (!kbhit); /* wait for a character */
kbhit = 0 ; /* clear receive interrupt bit */
return(scancode) ;
}
listing putchar.c
#include <ADI\ADUC831.h>
#include "kbd.h"
#include "lcd.h"

#define	MAX_COL_NUM	0x0f
#define	MAX_ROW_NUM	0x02

#define	CR	0x0d
#define	LF	0x0a
#define	FORM_FEED	0x0c
#define	BACKSPACE	0x08
unsigned char g_byRow = 0 ;
unsigned char g_byCol = 0 ;

unsigned char putchar (unsigned char c)
{
	if (c == CR)	{
		g_byCol = 0 ;
		if (g_byRow < MAX_ROW_NUM)
			g_byRow ++ ;
	}

	else if (c == FORM_FEED)
	{
		lcd_cmd(0x80) ;
		for(c = 0 ; c < 16 ; c ++)
			lcd_dat(' ') ;
		lcd_cmd(0xc0) ;
		for(c = 0 ; c < 16 ; c ++)
			lcd_dat(' ') ;
		g_byRow = 0 ;
		g_byCol = 0 ;
		c = FORM_FEED ;
	}
	else if (c == BACKSPACE)
	{
		if (g_byCol)
		{
			g_byCol -- ;
			if (g_byRow == 0)
				lcd_cmd(0x80 + g_byCol) ;
			else
				lcd_cmd(0xc0 + g_byCol) ;
			lcd_dat(' ') ;
		}
	}
	else
	{
		if (g_byRow == 0)
			lcd_cmd(0x80 + g_byCol) ;
		else
			lcd_cmd(0xc0 + g_byCol) ;
		lcd_dat(c) ;
		g_byCol ++ ;
		if (g_byCol > MAX_COL_NUM)
		{
			g_byCol = 0 ;
			if (g_byRow < MAX_ROW_NUM)
				g_byRow ++ ;
		}
	}
	return(c) ;
}


 Listing kbd.h
extern bit kbhit ;
extern char scancode ;
 listing lcd.h
void lcd_cmd1 (unsigned char cmd) ;
void lcd_dat1 (unsigned char dat) ;
void lcd_cmd (unsigned char cmd) ;
void lcd_dat (unsigned char dat) ;
void lcd_init () ;
void delay (unsigned int ms) ;
Listing kbd 5x5.c
#include <ADI\ADUC831.h>
#include <stdio.h>

unsigned char scancode ;
bit kbhit = 0 ;

unsigned char g_byScanCount = 0 ;
unsigned char g_byTheScanCount ;
unsigned char g_byRetCode ;
bit g_bKeyIsDown = 0 ;

// upper 3 bits of P0 and upper 2 bits of P2 are scan lines
sbit	SL0	= P0 ^ 5 ;
sbit	SL1	= P0 ^ 6 ;
sbit	SL2	= P0 ^ 7 ;
sbit	SL3	= P2 ^ 7 ;
sbit	SL4	= P2 ^ 6 ;
// lower 5 bits of P0 are return lines

const unsigned char KeyCodes[25] =
{
	0x0d,	// CR
	'F',
	'G',
	'H',
	8,		// backspace
	'D',
	'E',
	'-',
	'*',
	'/',
	'C',
	'+',
	'3',
	'6',
	'9',
	'B',
	'.',
	'2',
	'5',
	'8',
	'A',
	'0',
	'1',
	'4',
	'7'
} ;

void timer0 (void) interrupt 1 using 1
{
// this interrupt will occur every 10 ms (assuming ADuC831 @ 11.0592 MHz)
	TH0 = 0xDC ;
	if (g_byScanCount == 0)
		SL0 = 0 ;
	else if (g_byScanCount == 1)
		SL1 = 0 ;
	else if (g_byScanCount == 2)
		SL2 = 0 ;
	else if (g_byScanCount == 3)
		SL3 = 0 ;
	else
		SL4 = 0 ;
	#pragma asm
		nop ;
		nop ;
		nop ;
	#pragma endasm	// small delay to allow the scan lines to settle

	if (g_bKeyIsDown)
	{
		if (g_byTheScanCount == g_byScanCount)
		{
			if ((P0 & 0x1f) == 0x1f)
				g_bKeyIsDown = 0 ;
		}
	}
	else
	{
		g_byRetCode = P0 & 0x1f ;
		if (g_byRetCode == 0x1e)
			g_byRetCode = 0 ;
		else if (g_byRetCode == 0x1d)
			g_byRetCode = 1 ;
		else if (g_byRetCode == 0x1b)
			g_byRetCode = 2 ;
		else if (g_byRetCode == 0x17)
			g_byRetCode = 3 ;
		else if (g_byRetCode == 0x0f)
			g_byRetCode = 4 ;
		else
			g_byRetCode = 5 ;	// illegal return code
		if (g_byRetCode != 5)
		{
			scancode = KeyCodes[(g_byRetCode * 5) + g_byScanCount] ;
			g_bKeyIsDown = 1 ;
			g_byTheScanCount = g_byScanCount ;
			kbhit = 1 ;
		}
	}
	g_byScanCount ++ ;
	if (g_byScanCount > 4)
		g_byScanCount = 0 ;
	SL0 = 1 ;
	SL1 = 1 ;
	SL2 = 1 ;
	SL3 = 1 ;
	SL4 = 1 ;
}
 Listing 16x2lcd.c
#include <ADI\ADUC831.h>
#include "lcd.h"
#include "kbd.h"
unsigned char p2data = 0xff ;

void delay (unsigned int ms) {
unsigned int i = 0	;
for (i=0; i < ms ; i++) {
}
}

void lcd_cmd1 (unsigned char cmd)
{
// sends the 4 LSBits of cmd as a (half) command to the LCD
	p2data = (p2data & 0xc0) | (cmd & 0x0f) ;
	P2 = p2data ;
	p2data |= 0x10 ;	// EN high
	P2 = p2data ;
	p2data &= 0xef ;	// EN low
	P2 = p2data ;
}
void lcd_dat1 (unsigned char dat)
{
// sends the 4 LSBits of dat as a (half) data to the LCD
	p2data = (p2data & 0xc0) | (dat & 0x0f) | 0x20 ;	// A0 = high
	P2 = p2data ;
	p2data |= 0x10 ;	// EN high
	P2 = p2data ;
	p2data &= 0xef ;	// EN low
	P2 = p2data ;
}
void lcd_cmd (unsigned char cmd)
{
// sends cmd as a command to LCD
	lcd_cmd1(cmd >> 4) ;
	lcd_cmd1(cmd & 0x0f) ;
	delay(125) ;
}
void lcd_dat (unsigned char dat)
{
// sends dat as data to LCD
	lcd_dat1(dat >> 4) ;
	lcd_dat1(dat & 0x0f) ;
	delay(125) ;
}
void lcd_init ()
{
	lcd_cmd1(0x03) ;
	delay(2750) ;
	lcd_cmd1(0x03) ;
	delay(125) ;
	lcd_cmd1(0x03) ;
	delay(125) ;
	lcd_cmd1(0x02) ;
	delay(125) ;

	lcd_cmd(0x28) ;
	lcd_cmd(0x08) ;
	lcd_cmd(0x0c) ;
	lcd_cmd(0x06) ;
}
 Listing Calci.c
#include <ADI\ADUC831.h>
#include "kbd.h"
#include "lcd.h"
#include <stdio.h>
/* global variables */
#define	CR	0x0d
#define	LF	0x0a
#define	FORM_FEED	0x0c
#define	BACKSPACE	0x08

unsigned char operator ;
float fl1, fl2, fr;

void main ()
{
	TH0 = 0xDC ;	// for interrupt every 10 ms (assuming ADuC831 @ 11.0592 MHz)
	TL0 = 0x00 ;
	TMOD = 0x21 ;	// t0 = 16 bit timer, t1 = 8 bit auto-reload timer
	TCON = 0x55 ;
	IE = 0x82 ;		// enable timer0 interrupt
	lcd_init() ;
	while(1) 			// infinite loop
	{
		putchar(FORM_FEED) ;
		printf("Num1> ");
		scanf("%f",&fl1) ;			// get the first number from serial port
		putchar(FORM_FEED) ;
		printf("Operator> ") ;
		scanf("%c",&operator);	// get the operator from the serial port
		putchar(FORM_FEED) ;
		printf("Num2> ") ;
		scanf("%f",&fl2) ;			// get the second number from serial port
		putchar(FORM_FEED) ;
		switch(operator)			// according to the operator do the calculations
		{
			case	'+'	:	fr = fl1 + fl2 ;
						break ;
			case	'-'	:	fr = fl1 - fl2 ;
						break ;
			case	'*'	:	fr = fl1 * fl2 ;
						break ;
			case	'/'	:	fr = fl1 / fl2 ;
						break ;
			default	:	printf("Illegal operator") ;
			// if none of the above operators are present then the
			// entered operator is an illegal operator
		}	// end of switch

			// send the answer to the serial port
			// show 6 places after decimal point
		printf("\r= %.6f",fr) ;
		getchar() ;
	}		// end of while
}