Micro-C -- Help monitoring a switch on 8051

D

Dave Dunfield

That's completely off-topic here. This group is about the language
C, not how to use it for dealing with some micro-controller. But
since there's quite a number of C issues with your code I will
comment on this.

Agreed that it is OT, however some of the advice that was given,
although correct for a standard implementation, does not apply
in this situation and may confuse the OP.

Yes: Totally OT here - best to find someone familier with C on
tiny embedded controllers and ask for help.

Non-standard header files. But then you're missing essential ones
like <stdio.h>.

There is no operating system in this environment, hence there is no
"standard" I/O.

int main( void )
Missing return statememnt here, main() is supposed to return an int.

There is no operating system, hence nothing to return a value to.
If main ever returns (which it shouldn't in a normal embedded system),
the system will either hang in an infinite loop or restart depending on
how it is configured.

P2 = RowTable[row];
'P2' has never been defined, so that already should make your compiler
emit an error message.

P2 is the Special Function Register (SFR) used to access the 8051s
internal parallel I/O port #2 - defined in 8051reg.h

Lets assume you defined 'P2' to be a char. Then this function will
always return 0. So I guess the value of 'P2' must somehow be in-
fluenced by some user input (via reading the keyboard or whatever)
or it's completely useless - but your code doesn't has anything
that would make that happen.

Actually it does - P2 is a hardware register.


What's 'P0.1' supposed to be? You try to use that as the argument of
the setbit() and clrbit() functions - but it's neither a string nor
some value, so your compiler should get rather upset about that.

Since you asked - setbit() and clrbit() are macros, not functions, which
generate a single inline assembly SETB or CLR instruction - P0.1 is
the operand to that instruction (meaning port 0 - bit 1)


'P3' isn't defined anywhere in scope (and so it also hasn't a value
assigned to it).

8051 parallel I/O port #3.


Neither is 'P0' defined anywhere, nor is it's value (and, by proxy, the
value of your argument 'value') use anywhere in this function. So what's
all that supposed to be good for?

8051 output port 0.


Regards,
Dave (Author of Micro-C)
 
W

webzila

Hello,

I have to write a program for an 8051 micro-controller using micro-C to
monitor Switch 1 and if the switch in pushed the message "switch 1
pushed" should be displayed in the LCD. Also the microcontroller
should display in the LCD the value of the voltage applied to the input
of the ADC.

The above procedure should only execute once the user has entered
"1234" using a keypad that is attached to the 8051 microprocessor.

I think I can figure out the keypad entry function that will wait until
the user has entered "1234" before proceeding. Here is what I have for
that part so far...

I havent tested it with a micro-controller yet but this code compiled
using the Bipom Micro-Ide compiler.

#include <8051io.h>
#include <8051bit.h>
#include <8051reg.h>

#define MAX_ROWS 4
#define MAX_COLS 4

static char KeyTable[] = { '1', '2', '3', 'A',
'4', '5', '6', 'B',
'7', '8', '9', 'C',
'*', '0', '#', 'D'
};

static unsigned char RowTable[] = { 0xFE, 0xFD, 0xFB, 0xF7 };

char ScanKeypad();

main()
{
char key;

serinit(9600);
for( ;; )
{

key = ScanKeypad();

if( key == "1234" )
{
printf( "\nKey: '%c'", key );
//Proceed with the rest of the program from here
}

printf ("\nIncorrect Code Entered\n");
}
}


char ScanKeypad()
{
char row;
char col;

col = 0;

for( row=0; row<MAX_ROWS; row++ )
{
P2 = RowTable[row];

if( !(P2 & 0x80) )
col = 4;

if( !(P2 & 0x40) )
col = 3;

if( !(P2 & 0x20) )
col = 2;

if( !(P2 & 0x10) )
col = 1;

if( col != 0 )
{
delay(500);
return KeyTable[col-1 + row*MAX_COLS];
}
}
return 0;
}

Now I am not sure how to monitor the switch 1...I tried to make the
program for that specific requirement and here is what I got:

#include <8051io.h>
#include <8051bit.h>
#include <8051reg.h>
#define READ P0.1 /*READ=SET & WRITE=RESET*/
#define STROBE P0.2 /*DATA STROBE (ENABLE)*/
#define CTRL P0.0 /*CONTROL BIT (CONTROL=RESET & DATA=SET)*/

void InitLCD();
void WriteCtrl( unsigned char value );
void WriteData( unsigned char value );
void WriteCommon( unsigned char value );
void WriteLCD( unsigned char* message );
void CursorHome();
void CursorSet( unsigned char pos );

main()
{

/* Set the serial port to 9600 Baud */
serinit(9600);

while(1)
{
// Monitor Switch 1 - Display message on
// LCD if switch is pressed
while(!(P3 & 4))
{
InitLCD();
for(;;)
{
/* Write a simple message to the LCD */
CursorHome();
WriteLCD( "Switch 1 is pressed" );
}

}
}

//Functions to initialize and control the LCD
void InitLCD()
{
/* Wait a bit after power-up */
delay(200);
/* Initialize the LCD to 4-bit mode */
WriteCtrl(3);
delay(50);
WriteCtrl(3);
delay(10);
WriteCtrl(3);
delay(10);
WriteCtrl(2);
delay(10);
/* Function Set */
WriteCtrl(2);
delay(10);
WriteCtrl(8);
delay(10);
/* Display OFF */
WriteCtrl(0);
delay(10);
WriteCtrl(8);
delay(10);
/* Display ON */
WriteCtrl(0);
delay(10);
WriteCtrl(0x0F);
delay(10);
/* Entry mode */
WriteCtrl(0);
delay(10);
WriteCtrl(6);
delay(10);
/* Clear Screen */
WriteCtrl(0);
delay(10);
WriteCtrl(1);
delay(100);
/* Cursor home */
WriteCtrl(0);
delay(10);
WriteCtrl(2);
delay(100);
}
void CursorSet( unsigned char pos )
{
WriteCtrl(8 | ( (pos>>4) & 7 ) );
delay(1);
WriteCtrl(pos & 0x0F);
delay(1);
}
void CursorHome()
{
/* Cursor home */
WriteCtrl(0);
delay(1);
WriteCtrl(2);
delay(1);
}
void WriteLCD( unsigned char* message )
{
unsigned char i;
for( i=0; i<20; i++ )
{
if( !message )
break;
WriteData(message);
}
}
void WriteCtrl( unsigned char value )
{
clrbit(CTRL);
WriteCommon( value );
}
void WriteData( unsigned char value )
{
setbit(CTRL);
WriteCommon( value >> 4 );
WriteCommon( value );
}
void WriteCommon( unsigned char value )
{
clrbit(READ);
value = value & 0x0F;
value = value << 4;
P0 = P0 & 0x0F;
P0 = P0 | value;
setbit(STROBE);
delay(1);
clrbit(STROBE);
setbit(READ);
delay(1);
}

I believe that will work for monitoring the switch and displaying the
message on the LCD but now I really have no idea how to display in the
LCD the value of the voltage applied to the input of the ADC. Could
someone help with that please and verify that the programs posted above
would work considering the stated requirements?

Thank you
 
J

Jens.Toerring

webzila said:
I have to write a program for an 8051 micro-controller using micro-C to
monitor Switch 1 and if the switch in pushed the message "switch 1
pushed" should be displayed in the LCD. Also the microcontroller
should display in the LCD the value of the voltage applied to the input
of the ADC.

That's completely off-topic here. This group is about the language
C, not how to use it for dealing with some micro-controller. But
since there's quite a number of C issues with your code I will
comment on this.
The above procedure should only execute once the user has entered
"1234" using a keypad that is attached to the 8051 microprocessor.
I think I can figure out the keypad entry function that will wait until
the user has entered "1234" before proceeding. Here is what I have for
that part so far...
I havent tested it with a micro-controller yet but this code compiled
using the Bipom Micro-Ide compiler.

Hopefully, this is a standard compliant C compiler, otherwise you won't
get help here. Find a group that deals with issues of your compiler if
you get problems there. And, if that is possible, make your compiler emit
as many warnings as possible, you're probably going to be surprised...
#include <8051io.h>
#include <8051bit.h>
#include <8051reg.h>

Non-standard header files. But then you're missing essential ones
like said:
#define MAX_ROWS 4
#define MAX_COLS 4
static char KeyTable[] = { '1', '2', '3', 'A',
'4', '5', '6', 'B',
'7', '8', '9', 'C',
'*', '0', '#', 'D'
};
static unsigned char RowTable[] = { 0xFE, 0xFD, 0xFB, 0xF7 };
char ScanKeypad();

Make that

char ScanKeypad( void );

since the function obviously doesn't accept arguments.

int main( void )
{
char key;
serinit(9600);
for( ;; )
{
key = ScanKeypad();
if( key == "1234" )

What's that? 'key' is a character - but you try to compare it to the
address of a literal string. Your compiler should give you a big fat
warning for that and, of course, that won't work.

If you want to check if the ScanKeypad() function returned first the
character '1', then, on the next invocation, '2', then '3', and finally
'4' then you have to call the function four times and compare the
return value each time round. Or call it four times, stuff the return
values into a char array, append a trailing '\0' and use strcmp() to
compare the string to "1234". Hint: the "==" operator can't be used
to compare strings but just the addresses of strings.
{
printf( "\nKey: '%c'", key );
//Proceed with the rest of the program from here
}
printf ("\nIncorrect Code Entered\n");
}

Missing return statememnt here, main() is supposed to return an int.

BTW, indenting your code consistently makes it much easier to read.
char ScanKeypad()
{
char row;
char col;
for( row=0; row<MAX_ROWS; row++ )
{
P2 = RowTable[row];

'P2' has never been defined, so that already should make your compiler
emit an error message.
if( !(P2 & 0x80) )
col = 4;
if( !(P2 & 0x40) )
col = 3;
if( !(P2 & 0x20) )
col = 2;
if( !(P2 & 0x10) )
col = 1;
if( col != 0 )
{
delay(500);

Non-standard function... And even if it does what the name hints at,
i.e. waiting for a certain time, why would you use that here just
before returning from the function?
return KeyTable[col-1 + row*MAX_COLS];
}
}
return 0;
}

Lets assume you defined 'P2' to be a char. Then this function will
always return 0. So I guess the value of 'P2' must somehow be in-
fluenced by some user input (via reading the keyboard or whatever)
or it's completely useless - but your code doesn't has anything
that would make that happen.

And if you're at improving that function, why not define a few readable
names for the magic numbers you're using, like

#define COLUMN_4_BIT 0x80
#define COLUMN_3_BIT 0x40
#define COLUMN_2_BIT 0x20
#define COLUMN_1_BIT 0x10

or even

#define COLUMN_BIT( x ) ( 0x10 << ( ( x ) - 1 ) )

in order to use e.g. COLUMN_BIT(3) instead of 0x40? The next programmer
having to read your code will be grateful.
Now I am not sure how to monitor the switch 1...I tried to make the
program for that specific requirement and here is what I got:

You won't find out about that in comp.lang.c. Everything system or
hardware dependent is usually heavily frowned upon here.
#include <8051io.h>
#include <8051bit.h>
#include <8051reg.h>

Again non-standard header files.
#define READ P0.1 /*READ=SET & WRITE=RESET*/

What's 'P0.1' supposed to be? You try to use that as the argument of
the setbit() and clrbit() functions - but it's neither a string nor
some value, so your compiler should get rather upset about that.
#define STROBE P0.2 /*DATA STROBE (ENABLE)*/
#define CTRL P0.0 /*CONTROL BIT (CONTROL=RESET & DATA=SET)*/

Same here.
void InitLCD();

void InitLCD( void );
void WriteCtrl( unsigned char value );
void WriteData( unsigned char value );
void WriteCommon( unsigned char value );
void WriteLCD( unsigned char* message );
void CursorHome();

void CursorHome( void );
void CursorSet( unsigned char pos );

int main( void )
/* Set the serial port to 9600 Baud */
serinit(9600);
while(1)
{
// Monitor Switch 1 - Display message on
// LCD if switch is pressed
while(!(P3 & 4))

'P3' isn't defined anywhere in scope (and so it also hasn't a value
assigned to it).
{
InitLCD();
for(;;)
{
/* Write a simple message to the LCD */
CursorHome();
WriteLCD( "Switch 1 is pressed" );
}
}
}

You're missing a return statement and a closing '}' here. And what's
an infinite loop within an infinitive loop within an infinite loop
good for? Is a single infinity not ggod enough for you?
void WriteLCD( unsigned char* message )
{
unsigned char i;
for( i=0; i<20; i++ )
{
if( !message )
break;
WriteData(message);
}
}


What about

void WriteLCD( unsigned char* message )
{
size_t i;
for ( i = 0; *message && i < 20; i++ )
WriteData( *message++ );
}

And you probably would do yourself a favour if you would give the 20
a symbolic name, just guessing I would recommend

#define DISPLAY_WIDTH 20
void WriteCommon( unsigned char value )
{
clrbit(READ);
value = value & 0x0F;
value = value << 4;
P0 = P0 & 0x0F;
P0 = P0 | value;

Neither is 'P0' defined anywhere, nor is it's value (and, by proxy, the
value of your argument 'value') use anywhere in this function. So what's
all that supposed to be good for?
setbit(STROBE);
delay(1);
clrbit(STROBE);
setbit(READ);
delay(1);
}
I believe that will work for monitoring the switch and displaying the
message on the LCD but now I really have no idea how to display in the
LCD the value of the voltage applied to the input of the ADC. Could
someone help with that please and verify that the programs posted above
would work considering the stated requirements?

Since the programs probably won't even compile they are rather unlikely
to do what you want. But since here is really the wrong place to ask
about hardware specific programming issues you better find a different
place for this kind of questions.
Regards, Jens
 
J

Jens.Toerring

Agreed that it is OT, however some of the advice that was given,
although correct for a standard implementation, does not apply
in this situation and may confuse the OP.
Yes: Totally OT here - best to find someone familier with C on
tiny embedded controllers and ask for help.
There is no operating system in this environment, hence there is no
"standard" I/O.

Ok, didn't knew that he's on a freestanding implementation - could
have been some DOS-box where he tries to access some built-in hard-
ware.
P2 = RowTable[row];
'P2' has never been defined, so that already should make your compiler
emit an error message.
P2 is the Special Function Register (SFR) used to access the 8051s
internal parallel I/O port #2 - defined in 8051reg.h
Actually it does - P2 is a hardware register.

So that's some deep, non-standard magic - I was considering if the
Px would be macros, but then they wouldn't appear on the left and
right hand side of an assignment (and being used like P0.1)...
Since you asked - setbit() and clrbit() are macros, not functions, which
generate a single inline assembly SETB or CLR instruction - P0.1 is
the operand to that instruction (meaning port 0 - bit 1)

Thanks for the clarification. Do you know a more appropriate news-
group the OP could ask in?
Regards, Jens
 
L

Lawrence Kirby

....



Ok, didn't knew that he's on a freestanding implementation - could
have been some DOS-box where he tries to access some built-in hard-
ware.

The code does call printf(). In a freestanding implementation that need
not have anything to do with the standard library printf(), but it
probably does, especially seeing how it is called. Since printf() doesn't
appear to be defined in the program it is probably implementation-supplied
and most likely has a header you should include if you use it. Maybe that
was one of the headers the code includes already, probably not.

Lawrence
 
C

Chris Hills

Hi,

You are in the wrong place. Try comp.arch.embedded

Most of the people here will not understand embedded stuff. Their
answers will confuse you and whilst correct for their world will be
incorrect for yours.


I have to write a program for an 8051 micro-controller using micro-C to
monitor Switch 1 and if the switch in pushed the message "switch 1
pushed" should be displayed in the LCD. Also the microcontroller
should display in the LCD the value of the voltage applied to the input
of the ADC.

/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
\/\/\/\/\ Chris Hills Staffs England /\/\/\/\/\
/\/\/ (e-mail address removed) www.phaedsys.org \/\/
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
 
C

Chris Hills

Ok, didn't knew that he's on a freestanding implementation

Then why give advice?
BTW on an 8051 you should never use stdio... at least not for printf as
this if one function you shouldn't be using!

The place for 8051 questions is comp.arch.embedded




/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
\/\/\/\/\ Chris Hills Staffs England /\/\/\/\/\
/\/\/ (e-mail address removed) www.phaedsys.org \/\/
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
 
C

Chris Hills

Hello,

I have to write a program for an 8051 micro-controller using micro-C to

{
printf( "\nKey: '%c'", key );
//Proceed with the rest of the program from here
printf ("\nIncorrect Code Entered\n");

Don't use printf... that will save you about 4K. Use putch or
something similar. You should have the source for this in the library.

Regards
Chris

/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
\/\/\/\/\ Chris Hills Staffs England /\/\/\/\/\
/\/\/ (e-mail address removed) www.phaedsys.org \/\/
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
 
D

Dave Dunfield

Actually it does - P2 is a hardware register.
So that's some deep, non-standard magic - I was considering if the
Px would be macros, but then they wouldn't appear on the left and
right hand side of an assignment (and being used like P0.1)...

Not really magic - the I/O ports are addressed in the internal memory
address space in the 8051 (at least for direct addressing) - P2 is
simply declared as an external variable in internal memory in the
header file the lib has the actual definition which resolveds it to the
right SFR address.

Thanks for the clarification. Do you know a more appropriate news-
group the OP could ask in?

Probably comp.arch.embedded
 
D

Dave Dunfield

The code does call printf(). In a freestanding implementation that need
not have anything to do with the standard library printf(), but it
probably does, especially seeing how it is called. Since printf() doesn't
appear to be defined in the program it is probably implementation-supplied
and most likely has a header you should include if you use it. Maybe that
was one of the headers the code includes already, probably not.

printf() is prototyped in "8051io.h" which he includes. I have *MANY* different
toolsets for various CPU families, and many of the header files differ from
one family to another - so I use "<cpuname>" instead if "std", rather than some
complex system of directories and paths to select different sets of header
files.

Agreed - non-standard, but much about programming on tiny embedded
platforms is non-standard. I don't make any claims to be fully standard (not
really possible in this environment IMHO).

Regards,
 
D

Dave Dunfield

BTW on an 8051 you should never use stdio... at least not for printf as
this if one function you shouldn't be using!

As pointed out earlier, there is no stdio, however there is a "printf()"
which happens to write to the 8051 serial port in my default library.
Size of 8051 printf varies depending on memory model (addressing
differences), however it normally occupies about 500 bytes, which
makes it suitable in many cases.
 
C

Chris Hills

Richard Bos said:
Because in here, the normal assumption is that any implementation is
hosted unless explicitly declared freestanding.

Then perhaps the "normal assumption" is wrong.

The question explicitly stated 8051. If you know what one of those is
you are 99.998 certain that it is free standing. If you don't know what
an 8051 is why dive in?

Also it states "Micro-C" which gives a hint that it is not ISO-C. The
better response was the one most gave of: "Take it to a different NG."


Quite.
Richard

/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
\/\/\/\/\ Chris Hills Staffs England /\/\/\/\/\
/\/\/ (e-mail address removed) www.phaedsys.org \/\/
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top