This week I was looking over the Finite State Machine sketch that I previously created and I realized that I was relying alot on the built-in analogWrite(…) function. I did not want to have to rely on this function in order to write to the output pins so I have decided to make my own function that implements this functionality. This way, the sketch does not need to rely on a built-in library to write to and configure the pins.
I used the ATmega328 datasheet (on pages 91-92) to help me understand which registers I needed to modify to directly write the pin values to the registers.
I also used the Port Manipulation reference on the Arduino website to help me figure out which ports to use.
Write Data Function Design:
There are three ports that I needed to be aware of when writing to the Arduino board pins directly: Port B, Port C, and Port D.
Port B maps to digital pins 8 – 13 on the Arduino. Port C maps to the analog pins 0 – 5 on the Arduino. Port D maps to digital pins 0 – 7 on the Arduino.
Each pin within the ports can be configured to be either an input or an output by writing the corresponding value in the ports data direction register.
Each port has three primary registers associated with it:
DDR_ – The Port Data Direction Register – read/writePORT_ – The Port Data Register – read/writePIN_ – The Port Input Pins Register – read only
*Note: The _ should be replaced by the Port letter (B, C, or D) to use the desired port’s registers.
- The value written to the DDR_ register determines whether the PORT pin will be configured as an input or an output. Each bit in this register controls a different pin
- The PORT_ register is used for for the state of the outputs. You can read from this register to determine the values that are in each output pin or you can write to the register to directly write a value to the different pins.
- The PIN_ register is a read-only register that reads all of the data coming from the input pins.
For my Arduino Sketch that I am revising (which I talked about in my Update #3) I use the following registers:
const int GREEN_LED = 11; //Green LED signal going to RGB LED Strip
const int RED_LED = 10; //Red LED signal going to RGB LED Strip
const int BLUE_LED = 9; //Blue LED signal going to RGB LED Strip
const int FACE_DETECTED = 12; //Stimulates a face being detected
const int EXIT_IDLE = 13; // the number of the pushbutton pin
I use the digital pins #9 – 11 as output pins and the digital pins # 12-13 as input pins.
In order to configure them directly instead of calling the built-in pinMode function I would need to use Port B. I would need to set the DDRB register to the following value:
DDRB = DDRB | B00001110; // pins 9, 10, and 11 - outputs, pin 12 and 13 - inputs
This allows me to get rid of the pinMode(…) function calls when I initialize my pins as inputs and outputs.
The other design aspect for the write data function design that I need to think about is the pwm value, which is an input between 0 -255 that determines the duty cycle for the desired pin (how long it will be set high compared to how long it will be set low). Depending on the duty cycle, I then need to set the pin high and low for the appropriate amount of time. This is achieved using timers, which I discussed in my Update #4.
I basically need to have it so that my timer will keep the pin low (0) while its desired duty cycle is below the counter value and then keep the pin high (1) while its desired duty cycle is above the desired counter value.
Look back next week for the Write Data Function implementation.