Programming in C was not that hard for me, I have learned C++ and I have a previous experience with Java. I know the loops like for and while, conditional statement like if, variables like int, classes and libraries. I have also programmed an Arduino before, but I have never programmed in C or an micro controller on a lower level.
The problem was not the syntax of C, the problem was to understand the registers and how to use them for a specific function.
The micro controller used is ATTiny44.
ATTiny44 has 14 pins, 12 of them are for reading inputs and applying outputs. An input or an output can be either digital or analog. Any operation of a computer or a micro controller is simply a 0 or 1 which is 0v or 5v, digital is represented by 0 and 1 whereas the analog is represented as voltage range.
The micro controller should know if a specific pin will be used as an input or an output. If it is an input, the DDR register has to be 0 then it should know if it will write or read a specific pin. If the pin is an input and the operation is to write then the 0 is to deactivate pull up resistor and 1 is to activate pull up resistor, if the operation is to read then 0 is means 0v and 1 means 5v. If the pin is output, DDR registers has to be 1 then if it writes 0 means 0v and 1 means write 5v.
The process programmatically can be seen in the following code which I have used as the starting point in C programming.
Hardware is explained in Electronics documentation
/*
This code was created by Ahmad Fares on 4th-Dec-2017.
The code is used to switch on an LED when a Button is pressed.
MIT License
*/
#define F_CPU 1000000UL //Define the speed 1Mhz
#include <avr/io.h> //Include io library
#include <util/delay.h> //include delay library
int main (void)
{
DDRA = 0b00001000; // set PA3 as output in DDRA.
DDRB = 0b00000000; // set PB2 as input in DDRB.
PORTB = 0b00000100; // activate pull up resistor.
while(1) {
if(PINB == 0b00000000){ //Read PB2
PORTA = 0b00000000; //Switch on the LED
}else{
PORTA = 0b00001000; //Switch off the LED
}
}
}
It seems hard to define inputs and outputs at the way explained above, sometimes I forget a bit, sometimes I need to define only one pin not all of them so another way is to use bitwise method.
(register) |= (1 << (bit)) means to write 1 (register) &= ~(1 << (bit)) means to write 0 (register) & (1 << (bit)) to read statues.
The following code explains this method:
/*
This code was created by Ahmad Fares on 4th-Dec-2017.
The code is used to switch on an LED when a Button is pressed using bitewise method
MIT License
*/
#define F_CPU 1000000UL //Define the speed 1Mhz
#include <avr/io.h> //Include io library
#include <util/delay.h> //include delay library
int main (void)
{
DDRA |= (1 << PA3); // set PA3 as output in DDRA.
DDRB &= ~(1 << PB2); // set PB2 as input in DDRB.
PORTB |= (1 << PB2); // activate pull up resistor.
while(1) {
if(PINB & (1 << PB2)){ //Read PB2
PORTA &= ~(1 << PA3); //Switch on the LED
}else{
PORTA |= (1 << PA3);; //Switch off the LED
}
}
}
A much simpler way of defining inputs and outputs and writing zeros and ones is macron.
Using macron, I have been able to write a code in human understandable language rather than registers.
The following code explains the macron method
/*
This code was created by Ahmad Fares on 4th-Dec-2017.
The code is used to switch on an LED when a Button is pressed using macron method
MIT License
*/
#define F_CPU 1000000UL
#define setbit(register, bit) (register) |= (1 << (bit))
#define clearbit(register, bit) (register) &= ~(1 << (bit))
#define testbit(register, bit) (register) & (1 << (bit))
#include <avr/io.h>
#include <util/delay.h>
int main (void)
{
setbit(DDRA, PA3); // set PA3 as output in DDRA.
clearbit(DDRB, PB2); // set PB2 as input in DDRB.
setbit(PORTB, PA3); // activate pull up resistor.
while(1) {
if(testbit(PINB, PB2)){
setbit(PORTA, PA3);
}else{
clearbit(PORTA, PA3);
}
}
}
In sample code put also problems see notebook Descrip all the codes Push LED, Interrupt, delay, withoutPullUp
Add video of each code