need help configuring port to input in 8051 - c

The connection is as follows An infrared sensor circuit which yields 0 or 5v depending on closed or open circuit output line to port 2_0 pin of microcontroller 8051 philips.Problem is when i do this the circuit value are overridden by the current value on port 2_0 led always goes on.Here is my code(in keil c) i guess i have not configured P 2_0 as input properly
void MSDelay(unsigned int);
sbit led=P1^0;
void main()
{
unsigned int var;
P2=0xFF;
TMOD=0x20;
TH1=0xFD;
SCON =0x50;
TR1=1;
while(1)
{
var=P2^0;
if(var==0)
{
led=1;
SBUF='0';
while(TI==0);
TI=0;
MSDelay(250);
}
else
{
led=0;
SBUF='9';
while(TI==0);
TI=0;
MSDelay(100);
}
}
}
EDIT : I was facing a problem since the 8086 processor i was using had a fault in it. Would recommend anyone trying this to get a few spares when programming.

jschmier has a good point. Also the port may not be configured correctly, or is there something in the circuit that is causing the led to toggle off and on very quickly so it looks like it is on all the time.

You typically use the sbit data type for P2_0 to define a bit within a special function register (SFR).
From C51: READING FROM AN INPUT PORT (modified)
sfr P2 = 0xA0;
sbit P2_0 = P2^0;
...
P2_0 = 1; /* set port for input */
var = P2_0; /* read P2_0 into var */
It is important to note that sbit variables may not be declared inside a function. They must be declared outside of the function body.
Another option may be to read all 8 pins of P2 and then mask off the unwanted bits.
char var; /* define 8 bit variable */
P2 = 0xFF; /* set P2 for input */
var = P2; /* read P2 into var */
var &= 0x01; /* mask off unwanted bits */
Rather than read P2 or the P2_0 pin into an unsigned int (16 bits), you could use a char (8 bits) or single bit to save on memory.
char var;
...
var = P2;
or
bit var;
...
var = P2_0;
Another option may be to make the char bit-addressable.
char bdata var; /* bit-addressable char */
sbit var_0 = var^0; /* bit 0 of var */
...
var = P2; /* read P2 into var */
if(var_0 == 0) /* test var_0 (bit 0 of var char) */
{
...
}
You can find additional useful information in the Keil Cx51 Compiler User's Guide and related links.
Note: Most of my 8051 experience is in assembly. The C examples above may not be 100% correct.

Thank you so much... my coding works
And I learn how to define input port and read the data
#include<reg51.h>
#define opp P1
#define ipp P0
sbit op =P1^0;
sbit ip =P0^0;
main()
{
unsigned int value;
P0=0xFF;
value=P0;
value &=0x01;
if(value==0)
{
P1=0x01;
}
else
{
P1=0x00;
}
}

Related

UART overrun error when attempting to write to transmit holding register (U0THR)

So, I have a terminal connected to TxD0 and RxD0 pins. Let's say that I just want to test whether writing to it works after all.
I wrote few functions to make UART be able to read and write chars and strings. Although if I try to run it in the simulator, it gives me an overrun error.
Here are the functions in uart.c file:
void uart0_write(unsigned char reg_data)
{
while((U0LSR & (0x20)) != 0x20);/*wait until holding register is empty*/
U0THR = (int) reg_data;/*write to holding register*/
}
void uart0_write_str(char str[])
{
while(*str != '\0')/*check for EOF*/
{
uart0_write(*str);/*write a char*/
str++;
}
}
UART0 initialization function:
void uart0_init(void)
{
PINSEL0 = 0x05; /*set pin P0.0 to TXD0 and P0.1 RxD0 (TXD0 - 01; RxD0 - 01; 0101 = 0x05)*/
U0LCR = 0x83; /*set length for 8-bit word, set the stop bit, enable DLAB*/
U0IER = (1<<0) | (1<<1);/*enable RBR and THR interrupts*/
U0FCR = 0xC7; /*enable FIFO; reset Tx FIFO; set interrupt after 14 characters*/
/*Baud rate configured to 9600 Baud (from lecture notes)*/
U0DLL = 0x9D;
U0DLM = 0x0;
U0LCR = 0x03; /*8-bit character selection; disable DLAB*/
}
Exemplary use in main:
int main(void)
{
char *introMsg;
introMsg = "Hello World\n";
systemInit();
ADC_init();
timer0_init();
uart0_init();
uart0_write_str(introMsg);
/*or: */
while(1)
{
uart0_write('c');
}
return 0;
}
With these demonstrative code snippets the UART should work properly as I saw elsewhere on the web.
But when attempting to run it, it doesn't print anything and the OE pops up.
What am I doing wrong? I'm only starting to dive into the depths of bare metal programming, so there might be some bug that I didn't notice.
I'd welcome any insights!
Stay home,
Jacob

Array's data is changed if I don't printf it

I am writing a C program on Eclipse to communicate from my ARM Cortex M4-F microcontroller in I2C with its master, another MCU.
In my I2C library, I use a static global variable to store all the parameters of the communication (address, lenghts, data buffers). The issue is that a part (an array containing the data to be transmitted, which are 8 bits integers) of this variable gets modified when the interrupt (Start condition followed by the slave's address on the I2C bus) happens, even before executing the code I put the handler. It gets assigned to 8, whatever the initial value.
I tried to put breakpoints basically everywhere, and a watchpoint on the variable, the changes arises seemingly from nowhere, not in the while loop, and before the call to my_I2C_Handler(), so the interrupt is the cause apparently.
I also tried setting the variable as volatile, but that changed nothing.
I noticed one interesting thing: putting a printf of the array's data during my_I2C_Init() or my_SlaveAsync(), like so:
printf("%d\n", req.tx_data[0]);
corrects this problem, but why? I want to remove all prints after debugging.
#include <stdint.h>
#include "my_i2c.h"
void I2C1_IRQHandler(void)
{
printf("\nI2C Interrupt\n");
my_I2C_Handler(MXC_I2C1); // MXC_I2C1 is a macro for the registry used
}
int main(void)
{
int error = 0;
printf("\nStarting I2C debugging\n");
// Setup the I2C
my_I2C_Shutdown(MXC_I2C1);
my_I2C_Init(MXC_I2C1);
NVIC_EnableIRQ(I2C1_IRQn); // Enable interrupt
my_I2C_SlaveAsync(MXC_I2C1); // Prepare to receive communication
while (1)
{
LED_On(0);
LED_Off(0);
}
printf("\nDone testing\n");
return 0;
}
The structure of the request containing the parameters of the communication is like this:
typedef struct i2c_req i2c_req_t;
struct i2c_req {
uint8_t addr; // I2C 7-bit Address
unsigned tx_len; // Length of tx data
unsigned rx_len; // Length of rx
unsigned tx_num; // Number of tx bytes sent
unsigned rx_num; // Number of rx bytes sent
uint8_t *tx_data; // Data for mater write/slave read
uint8_t *rx_data; // Data for master read/slave write
};
Is declared like so in the beginning of the file:
static i2c_req_t req;
and assigned this way in my_I2C_Init():
uint8_t rx[1] = {0};
uint8_t tx[1] = {12};
req.addr = 0xAA;
req.tx_data = tx;
req.tx_len = 1;
req.rx_data = rx;
req.rx_len = 1;
req.tx_num = 0;
req.rx_num = 0;
Many thanks for your help

Writing on serial port COM1 in a kernel from scratch

I'm writing an i386 ELF kernel from scratch. I need to be able to write to the serial port COM1.
I have wrote two functions, serial_init() is called every time I call printk(char* str) which calls for each iteration for each character serial_putc(char c).
#define SERIAL_COM1 (0x03f8)
void serial_putc(char c)
{
char* serial = (char*)SERIAL_COM1;
while ((serial[5] & 0x20) == 0);
serial[0] = c;
}
void serial_init()
{
char* serial = (char*)SERIAL_COM1;
serial[1] = 0x00;
serial[3] = 0x80;
serial[0] = 0x03;
serial[1] = 0x00;
serial[3] = 0x03;
serial[2] = 0xc7;
serial[4] = 0x0b;
}
The line protocol is:
38400 bauds
8 bits per word
No parity check
1 stop bit
I'm using qemu-system-i386 -serial stdio -kernel ./kernel to test my kernel but it doesn't print anything on the output on the serial port.
Since I needed to write outb and inb here is the code:
inline void outb(unsigned int port, unsigned char val)
{
asm volatile ("outb %%al,%%dx": :"d" (port), "a" (val));
}
inline unsigned char inb(unsigned int port)
{
unsigned char ret;
asm volatile ("inb %%dx,%%al":"=a" (ret):"d" (port));
return (ret);
}
I still can't get an ouput.
What am I doing wrong ?
You should look at outb() and inb(), you can't write on your COM1 address like that.

PIC pass SFR address to function in C

I am attempting to pass a reference to an I/O pin as an function argument on a PIC24F MCU using C. For PICs, the device header file provides access to the i/o buffer registers via:
LATAbits.LATA2 = 0; // sets the pin (RA2 in this case) low.
if (PORTAbits.RA3) { // reads the state of the pin. (RA3)
I want to do something like this:
int main() {
Configure(); // Sets up peripherals, etc.
WaitForHigh(PORTAbits.RA3); // waits for pin RA3 to go hi.
...
return 0;
}
void WaitForHigh( ?datatype? pin_reference ) {
while( !pin_reference ); // Stays here until the pin goes hi.
}
So what datatype am I trying to pass here? And what's actually going on when I poll that pin? Below, I copy a relevant portion from the PIC24F device header that I'm using in case it helps.
#define PORTA PORTA
extern volatile unsigned int PORTA __attribute__((__sfr__));
typedef struct tagPORTABITS {
unsigned RA0:1;
unsigned RA1:1;
unsigned RA2:1;
unsigned RA3:1;
unsigned RA4:1;
unsigned RA5:1;
} PORTABITS;
extern volatile PORTABITS PORTAbits __attribute__((__sfr__));
Thank you in advance!
As an alternative to using a macro, a function can accept both the PORT register address (or latch register address, eg. LATA in the case of a pin configured for output) and the mask of the bit in the register that is needed. For example:
#include<p24FV32KA301.h> // defines both PORTA and _PORTA_RA3_MASK
void WaitForHigh( volatile unsigned int * port, pin_mask ) {
while( !(*port & pin_mask) ); // Stays here until the pin goes hi.
}
int main()
{
...
WaitForHigh( &PORTA, _PORTA_RA3_MASK ); // waits for pin RA3 to go hi.
...
return 0;
}
Please, note that the PORT bit values are obtained through a bit field, so, answering your question, you can't. Bit fields doesn't have address, so you cannot pass it as a pointer to a function.
Instead, you could use a Macro:
#define WaitForHigh(p) do{while(!(p));}while(0)
It is true that macros has it's draw backs on code readability, yet, given that proper care is taken, there are situations where they're the best solution. It is arguable if macro is the best solution in this Q&A, yet it is important to mention.
Thanks to the commenters for the suggestions to improve the macro safeness.
You can combine preprocessor processing with a function to get what you wan along with compile time checking of the symbols. For example:
#define PORT_FUNC(f, p, b) f(p, b)
#define WaitForHigh(p, b) PORT_FUNC(WaitForHighImp, &p, _ ##p## _ ##b## _MASK)
void WaitForHighImp(volatile unsigned* p, unsigned char mask)
{
while (!(*p & m))
;
}
int main()
{
WaitForHigh(PORTA, RA3);
}
The advantage of this approach is that you online say "PORTA" once and "RA3" once at the time of the call, you make sure the bit name is present in the port and that the bit is present.

Embedded C: Registers Access

Suppose we want to write at address say 0xc000, we can define a macro in C as:
#define LCDCW1_ADDR 0xc000
#define READ_LCDCW1() (*(volatile uint32_t *)LCDCW1_ADDR)
#define WRITE_LCDCW1(val) ((*(volatile uint32_t *)LCDCW1_ADDR) = (val))
My question is that when using any micro-controller, consider an example MSP430, P1OUT register address is 0x0021.
But when we use P1OUT=0xFFFF; // it assigns P1OUT a value 0xFFFF.
My question is how does it write to that address e.g. in this case 0x0021.
The IDE is IAR. I found in header msp430g2553.h below definition:
#define P1OUT_ (0x0021u) /* Port 1 Output */
DEFC( P1OUT , P1OUT_)
I suppose it is defining the address, but where are the other macros to write or read.
Could anyone please explain the flow that how P1OUT writes at that particular address location? Also do let me know what does u mean in 0x0021u ?
Thanks
So far the details I have found are :
in msp430g2553.h
#ifdef __IAR_SYSTEMS_ICC__
#include "in430.h"
#pragma language=extended
#define DEFC(name, address) __no_init volatile unsigned char name # address;
#define DEFW(name, address) __no_init volatile unsigned short name # address;
#define DEFXC volatile unsigned char
#define DEFXW volatile unsigned short
#endif /* __IAR_SYSTEMS_ICC__ */
#ifdef __IAR_SYSTEMS_ASM__
#define DEFC(name, address) sfrb name = address;
#define DEFW(name, address) sfrw name = address;
#endif /* __IAR_SYSTEMS_ASM__*/
#define P1OUT_ (0x0021u) /* Port 1 Output */
DEFC( P1OUT , P1OUT_)
The io430g2553.h says
__no_init volatile union
{
unsigned char P1OUT; /* Port 1 Output */
struct
{
unsigned char P0 : 1; /* */
unsigned char P1 : 1; /* */
unsigned char P2 : 1; /* */
unsigned char P3 : 1; /* */
unsigned char P4 : 1; /* */
unsigned char P5 : 1; /* */
unsigned char P6 : 1; /* */
unsigned char P7 : 1; /* */
}P1OUT_bit;
} #0x0021;
Can some one explain what the above definition does? The details I found in MSP430 IAR C/C++ Compiler:
Example of using __write and __read
The code in the following examples use memory-mapped I/O to write to an LCD
display:
__no_init volatile unsigned char LCD_IO # address;
size_t __write(int Handle, const unsigned char * Buf,
size_t Bufsize)
{
size_t nChars = 0;
/* Check for stdout and stderr
(only necessary if file descriptors are enabled.) */
if (Handle != 1 && Handle != 2)
{
return -1;
}
for (/*Empty */; Bufsize > 0; --Bufsize)
{
LCD_IO = * Buf++;
++nChars;
}
return nChars;
}
The code in the following example uses memory-mapped I/O to read from a keyboard:
__no_init volatile unsigned char KB_IO # 0xD2;
size_t __read(int Handle, unsigned char *Buf, size_t BufSize)
{
size_t nChars = 0;
/* Check for stdin
(only necessary if FILE descriptors are enabled) */
if (Handle != 0)
{
return -1;
}
for (/*Empty*/; BufSize > 0; --BufSize)
{
unsigned char c = KB_IO;
if (c == 0)
break;
*Buf++ = c;
++nChars;
}
return nChars;
}
Does any one know?
This is "how does the compiler generate the code from what I've written", and only the compiler writers will actually be able to answer that for you.
Clearly, there are several non standard C components in the code above __no_init, the use of #, etc. In my reading of this, it tells the compiler that "this is a HW port, that provides an unsigned char, and it's address is 0xd2". The compiler will produce the right kind of instructions to read and write such a port - exactly how that works depends on the compiler, the processor that the compiler is producing code for, etc.
The P10out structure defines bitfields, which is part of the C standard. Google is your friend here.
Indirection operator (unary *) returns l-value equivalent to the value at pointer address.
#define LCDCW1_ADDR 0xc000
void f()
{
uint32_t a = *(volatile uint32_t *)LCDCW1_ADDR; //reading from LCDCW1_ADDR
*(volatile uint32_t *)LCDCW1_ADDR = 0xffff; //writing to LCDCW1_ADDR
/*...*/
}
Basically, compiler is smart enough to see, that a = *addr; expression means "read value from addr address and put it to a. At the same time *addr = 0xffff will be interpreted like "put 0xffff to addr address"
In your case you can use your READ_LCDCW1() macro both on left and right hand side of assignment operator. There is no need for separate WRITE_LCDCW1(val) macro. We can rewrite the previous code as:
#define LCDCW1_ADDR 0xc000
#define LCDCW1 (*(volatile uint32_t *)LCDCW1_ADDR)
void g()
{
uint32_t a = LCDCW1; //reading from LCDCW1_ADDR
LCDCW1 = 0xffff; //writing to LCDCW1_ADDR
/*...*/
}
P1OUT macro from IAR is most probably defined the same way as LCDCW1 above (if you follow the DEFC() definition you will eventually find something like it).
My question is that when using any micro-controller, consider an
example MSP430
You're not using any micro-controller, you are using an MSP430. It has memory-mapped IO (which is really nice to use for us programmers). The memory mapping will vary based on device. The answers to any of the address related questions lie within your specific device's User's Guide. TI makes very good User Guide's. Find the one for your specific device and read it thoroughly.
My question is how does it write to that address e.g. in this case
0x0021. The IDE is IAR.
Compiler glue code. Your compiler vendor will supply you with the necessary headers, macros and functions to write to your device addresses. Use the compiler vendor's code unless you can absolutely prove that it is not working for your case (with IAR I would assume that 99.9% it works, you get what you pay for. Possibly with a brand new device there are bugs in the implementation, but probably not unless you can prove it).
Also do let me know what does u mean in 0x0021u ?
From what you've posted, that is the base address for port 1. It looks like you have 8 pins on port 1 you can control.
#pragma language=extended
From this point on you must assume that there are all sorts of "magical" (aka non-standard C) things that will be happening. You can infer what you think the compiler is doing (and for the most part it is reasonably clear), however this is implementation defined, meaning only IAR compiler supports what will happen next. Look at the compiler docs for specific commands and meanings. Most notably the __no_init and the # symbol are non-standard. The __no_init will not initialize the variable at C startup (i.e. before main() runs). The # looks like an absolute address instruction that will be given to the linker (I may be wrong here).
__no_init volatile union
{
unsigned char P1OUT; /* Port 1 Output */
struct
{
unsigned char P0 : 1; /* */
unsigned char P1 : 1; /* */
unsigned char P2 : 1; /* */
unsigned char P3 : 1; /* */
unsigned char P4 : 1; /* */
unsigned char P5 : 1; /* */
unsigned char P6 : 1; /* */
unsigned char P7 : 1; /* */
}P1OUT_bit;
} #0x0021;
This defines a way to get at specific bits of the byte for port 1. This lets you manipulate the IO pins. Some would say OMG bitfields are portable, the are implementation defined! Yes, they are right, but IAR is the implementor, so in this case just trust them to do the right thing.
Final note, you probably just want to use the IAR macros as defined. You paid a lot of money for them (unless you are using the free kickstart edition). You can concentrate on writing your app and not manipulating bits this way. IAR does do a good job of standardizing their names, so you can also use the same code (or very similar) on related parts. If you switch to a different compiler all this goes out the window and you'll have to do it the way of the new compiler. Good and bad points to this approach, probably no "right" answer.

Resources