views:

289

answers:

6

I am using an IC, DS1620 to read 1 bit serial data coming on a single line. I need to read this data using one of the ports of ARM microcontroller (LPC2378). ARM ports are 32 bit. How do I get this value into a 1 bit variable?

Edit: In other words I need direct reference to a port pin.

+5  A: 

there are no 1 bit variables, but you could isolate a particular bit for example:

uint32_t original_value = whatever();
uint32_t bit15 = (original_value >> 15) & 1; /*bit15 now contains either a 1 or a 0 representing the 15th bit */

Note: I don't know if you were counting bit numbers starting at 0 or 1, so the >> 15 may be off by one, but you get the idea.

The other option is to use bit fields, but that gets messy and IMO is not worth it unless every bit in the value is useful in some way. If you just want one or two bits, shifting and masking is the way to go.

Overall, this article may be of use to you.

Evan Teran
Another question - How do get ARM microcontroller port value into a 32 bit variable in the first place?
Alex Xander
well that is something that is processor specific. One x86 you would use some assembly or compiler intrinsic to perform an `in` or `out` instruction to read and write I/O ports.
Evan Teran
On an ARM the I/O port is probably just mapped to a particular memory location--"memory-mapped registers". Have a good read of the LPC2378 manuals. There is probably a C header file available that provides names for all these registers.
Craig McQueen
Depending on the rest of your code you might not need the shift. You can do the following instead:uint32_t bit15 = (original_value) Note: The (1 << 15) will be calculated only once at compile time.
Ron
@Ron: good point, if the goal is to just do a boolean test then your suggestion could potentially compiler to slightly better code.
Evan Teran
+2  A: 

For your CPU the answer from Evan Teran should be used. I just wanted to mention the bit-band feature of some other ARM CPU's like the Cortex-M3. For some region of RAM/Peripherals all bits are mapped to a separate address for easy access.

See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337e/Behcjiic.html for more information.

Ron
+1  A: 

It's simple if you can access the port register directly (I don't have any experience with ARM), just bitwise AND it with the binary mask that corresponds to the bit you want:

var = (PORT_REGISTER & 0x00008000);

Now var contains either 0 if the 15th bit is '0' or 0x00008000 if the 15th bit is '1'.

Also, you can shift it if you want to have either '0' or '1':

var = ((PORT_REGISTER & 0x00008000) >> 15);
Marcelo MD
A more readable form of 0x00008000 is `(1 << 15)` which the assembler or compiler will calculate during the translation time, not run-time.
Thomas Matthews
A: 

The header file(s) which come with your compiler will contains declarations for all of the microcontroller's registers, and the bits in those registers.

In this specific article, let's pretend that the port input register is called PORTA, and the bit you want has a mask defined for it called PORTA15.

Then to read the state of that pin:

PinIsSet = (PORTA & PORTA15) == PORTA15;

Or equivalently, using the ternary operator:

PinIsSet = (PORTA & PORTA15) ? 1 : 0;

As a general point, refer to the reference manual for what all the registers and bits do. Also, look at some examples. (This page on the Keil website contains both, and there are plenty of other examples on the web.)

Steve Melnikoff
A: 

In LPC2378 ( as the other LPC2xxxx microcontroller family ), I/O ports are in system memory, so you need to declare some variables like this:

#define  DALLAS_PIN (*(volatile unsigned long int *)(0xE0028000)) /* Port 0 data register */
#define  DALLAS_DDR (*(volatile unsigned long int *)(0xE0028008)) /* Port 0 data direction reg */
#define  DALLAS_PIN (1<<15)

Please note that 0xE0028000 is the address for the data register of port0, and 0xE0028008 is the data direction register address for port0. You need to modify this according to the port and bit used in your app. After that, in your code function, the code or macros for write 1, write 0 and read must be something like this:

#define  set_dqout()    (DALLAS_DDR&=~DALLAS_PIN)   /* Let the pull-up force one, putting I/O pin in input mode */
#define  reset_dqout()  (DALLAS_DDR|=DALLAS_PIN,DALLAS_PORT&=~DALLAS_PIN) /* force zero putting the I/O in output mode and writing zero on it */
#define  read_dqin()    (DALLAS_DDR&=~DALLAS_PIN,((DALLAS_PORT & DALLAS_PIN)!= 0)) /* put i/o in input mode and test the state of the i/o pin */

I hope this can help.

Regards!

German Ortiz
A: 

If testing for bits, it is good to keep in mind the operator evaluation order of C, e.g.

if( port & 0x80 && whatever() )

can result in unexpected behaviour, as you just wrote

if( port & (0x80 && whatever()) )

but probably ment

if( (port & 0x80) && whatever() )
e8johan