I'm interested in writing a C program without the Arduino IDE and related libraries and am trying to figure out how I can access the GPIO pins for read and write.
My assumption is that the GPIO pins are - at the hardware layer - just memory addresses, and so if I know what their address is I can send/receive data to and from them.
- For writing to the digital pins, do I just send an
int
with a value of0
or1
to the pin's address? If so, what might that code look like? Can I then assume I could poll that address for a value, which would be either0
or1
? - Can I assume the same for analog pins, but instead of binary values, I'd get an integral value between
0
and1023
?
And if I'm way off here, and pins are not accessed via memory addresses, then how?
Again, the solution I'm looking for wouldn't involve Arduino software, just the Arduino hardware (an AVR or ARM MCU). Bonus points for C pseudo-code examples! Thanks in advance!
1 Answer 1
In theses cases you are right, using register address is the way to read/write data from/to digital pins. In the case you use analog input, the process is similar but you have to follow some procedures before getting the value of the data.
For AVR micro-controllers these registers are: DDRn – Data Direction Register PORTn – Port Output data Register PINn – Port Input Register n- Indicates the port name i.e. A, B, C & D If you have arduino board and want to use these pins, look for mapping pictures about arduino and avr pins.
The following is an example from the Arduino website.
DDRD is the direction register for Port D (Arduino digital pins 0-7). The bits in this register control whether the pins in PORTD are configured as inputs or outputs so, for example:
DDRD = B11111110; // sets Arduino pins 1 to 7 as outputs, pin 0 as input
DDRD = DDRD | B11111100; // this is safer as it sets pins 2 to 7 as outputs
// without changing the value of pins 0 & 1, which are RX & TX
See the bitwise operators reference pages and The Bitmath Tutorial in the Playground
PORTD is the register for the state of the outputs. For example;
PORTD = B10101000; // sets digital pins 7,5,3 HIGH
You will only see 5 volts on these pins however if the pins have been set as outputs either by using the DDRD
register directly or by using the pinMode()
function.
For analog read
You just need to include the headers and start using the registers. They hold the equivalent hexadecimal values for your microcontroller. And the procedure is described in the datasheet. All you have to do is to translate it to code.
// this code scans ADC1 for an analog signal upon request, using 8Mhz processor clock
#include <avr/io.h>
#include <stdint.h> // needed for uint8_t
int ADCsingleREAD(uint8_t adctouse)
{
int ADCval;
ADMUX = adctouse; // use #1 ADC
ADMUX |= (1 << REFS0); // use AVcc as the reference
ADMUX &= ~(1 << ADLAR); // clear for 10 bit resolution
// 128 prescale for 8Mhz
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
ADCSRA |= (1 << ADEN); // Enable the ADC
ADCSRA |= (1 << ADSC); // Start the ADC conversion
while(ADCSRA & (1 << ADSC)); // waits for the ADC to finish
ADCval = ADCL;
ADCval = (ADCH << 8) + ADCval; // ADCH is read so ADC can be updated again
return ADCval;
}
int main(void)
{
int ADCvalue;
while (1)
{
ADCvalue = ADCsingleREAD(1);
// ADCvalue now contains an 10bit ADC read
}
}
For more information about analog read, see this.
-
Thank you so much @bpinhosilva (+1) - however, I'm not 100% sure you understand my exact question. Take
DDRD
for instance. In your code example above you have:DDRD = B11111110
. You state that this sets Arduino pins 1 - 7 asOUTPUT
. ButDDRD
is a variable... but what library is it define inside of? In other words, what#include
statement do I need to add to my source code to gain access toDDRD
? If the answer is one of the Arduino libraries, then this doesn't help me! I need non-Arduino access to the AVR/ARM pins! Thanks again!smeeb– smeeb2015年05月12日 19:27:43 +00:00Commented May 12, 2015 at 19:27 -
I just noticed your 2nd code sample above includes
avr/io.h
- if you can confirm thatDDRD
(and other similar port/register vars) are defined in this file, I think I'm all set!smeeb– smeeb2015年05月12日 19:29:23 +00:00Commented May 12, 2015 at 19:29 -
1You use #include <avr/io.h>. This is a standard library for avr units. Inside that you find definitions for these registers. Other point is that I am assuming you use Arduino but want to develop with a different IDE. So you need to find the equivalent avr pin to your board's labels. That's why the code says Arduino pinx and so on.bpinhosilva– bpinhosilva2015年05月12日 19:30:40 +00:00Commented May 12, 2015 at 19:30
-
1These names are not variables, they are mnemonics for addresses so you can easily remember them. You are welcome!bpinhosilva– bpinhosilva2015年05月12日 19:32:30 +00:00Commented May 12, 2015 at 19:32
-
Thanks again @bpinhosilva (+1 again) - last followup question: I am wondering what the equivalent is for ARM registers. I found this EE.SE question but no one has answered it. Any idea what I would use for an ARM MCU? Thanks again!smeeb– smeeb2015年05月12日 19:32:45 +00:00Commented May 12, 2015 at 19:32
DDRD
does not come from the Arduino "language", it's defined by avr-libc. Just#include <avr/io.h>
and you get all the I/O registers you see in the MCU datasheet.