Microcontrollers 101
Introduction
As an introduction to working with microcontrollers, I'll showcase 9 simple programs written in c
.
Our microcontroller will switch through these 9 programs with button S4
- next program - and S3
- previous program.
- 8-bit counter that counts up in binary code (0-255)
- Reverse of p1 - count down in binary
- 8-bit count up in Gray code
- Reverse of p3 - count down in Gray
- 2x4-bit count up in BCD code (0-99)
- Reverse of p5 - count down in BCD
- 3-bit snake moving side-to-side (3 LEDs next to each other moving in a block in an infinite loop)
- Stack building up ('move' a LED from right to left and keep it at the end until all LEDs are on)
- 6-bit random number generator with a
seed = 1110011
Prerequisites
Configured to run on PIC24FJ128GA010 (might need a few changes to outside functions to rework on a different controller).
Some tutorials I used:
Implementation
Base (switching, buttons)
In an infinite loop I'm checking if any buttons were pressed - and if so - I'm changing the current program index in a program
variable. Then using if-statements I'm checking which program to run.
//main.c
int main ( void ){
SYS_Initialize ( ) ; //initialize the app
TIMER_SetConfiguration ( TIMER_CONFIGURATION_RTCC ) ;
ADC_SetConfiguration ( ADC_CONFIGURATION_AUTO_SAMPLE_CONVERT ) ;
int program = 1; //keep track of which program is running
while ( 1 ){ //infinite loop
if (BUTTON_IsPressed ( BUTTON_S3 )){ //previous program
program--;
if (program == 0) program = 9; //edge case
}
if (BUTTON_IsPressed ( BUTTON_S4 )){ //next program
program++;
if (program == 10) program = 1; //edge case
}
if (program == 1){//check which program to run
count_up();
}
if (program == 2){
count_down();
}
if (program == 3){
count_up_gray();
}
if (program == 4){
count_down_gray();
}
if (program == 5){
count_up_bcd();
}
if (program == 6){
count_down_bcd();
}
if (program == 7){
snake();
}
if (program == 8){
stack();
}
if (program == 9){
pseudo();
}
}
return 0;
}
Count-up in binary
The PIC24 default config on MPLAB x IDE includes LATA
- which controls all 8 LEDs at the same time by converting a given value into binary and displaying it. This means making a binary counter doesn't even involve using binary code lol.
The delay()
function is called so we can see the LEDs changing - without it the microcontroller works a little too fast.
void count_up(){//abort counting when either button is pressed
for(int i = 0; i <= 255; i++){ //count up 0-255
LATA = i; //display i on LEDs
delay(200); //wait - otherwise too quick
if(BUTTON_IsPressed(BUTTON_S3) | BUTTON_IsPressed(BUTTON_S4)){
Break;
} //exit func if buttons pressed
}
}
Count-down in binary
Simply reverse the for-loop.
void count_down(){
for(int i = 255; i >= 0; i--){ //count down 255-0
LATA = i;
delay(200);
if(BUTTON_IsPressed(BUTTON_S3) | BUTTON_IsPressed(BUTTON_S4)){
break;
}
}
}
Count-up in Gray
As you've seen in the linked above tutorial, converting a decimal number to Gray involves moving bits.
void count_up_gray(){
for(int i = 0; i < 256; i++){ //count up 0-255
int gray = i ^ (i >> 1); //convert to gray - move bit
LATA = gray;
delay(250);
if(BUTTON_IsPressed(BUTTON_S3) | BUTTON_IsPressed(BUTTON_S4)){
break;
}
}
}
Count-down in Gray
Again let's just reverse the for-loop.
void count_down_gray(){
for(int i = 255; i >= 0; i--){ //count down 255-0
int gray = i ^ (i >> 1); //convert to gray
LATA = gray;
delay(250);
if(BUTTON_IsPressed(BUTTON_S3) | BUTTON_IsPressed(BUTTON_S4)){
break;
}
}
}
Count-up in BCD
This one is a little trickier - BCD is a binary-coded decimal, which uses 4 bits to code a single digit. That's why our counter is 2x4 - so we have tens and an ints value. When displaying it on 8 LEDs we first push the tens to the far-left 4 bits and then add the ints.
void count_up_bcd(){
for(int i = 0; i < 100; i++) { //count up 0-99
int bcd1 = i / 10; //tens
int bcd2 = i % 10; //units
LATA = (bcd1 << 4) | bcd2; //tens go on first 4 LEDs, then units
delay(250);
if(BUTTON_IsPressed(BUTTON_S3) | BUTTON_IsPressed(BUTTON_S4)){
break;
}
}
}
Count-down in BCD
void count_down_bcd(){
for(int i = 99; i >= 0; i--) { //count down 99-0
int bcd1 = i / 10; //tens
int bcd2 = i % 10; //units
LATA = (bcd1 << 4) | bcd2; //tens go on first 4 LEDs, then units
delay(250);
if(BUTTON_IsPressed(BUTTON_S3) | BUTTON_IsPressed(BUTTON_S4)){
break;
}
}
}
3-bit Snake
First I declared a list of numbers
that contains all possible positions of the "snake". Since it's a 3-bit block moving on an 8-bit space we only have 6 possible combinations.
To control which position to display we have index
- it's passed to the numbers list - and to control the direction of reading the list we have direction
- either to the left or to the right.
void snake(){
int numbers[] = {7, 14, 28, 56, 112, 224}; //all positions of snake
int index = 0; //which position to display
int direction = 1; //1 to the left, -1 to the right
while (1){ //breaks if buttons=pressed
LATA = numbers[index]; //display led position
delay(250);
index += direction; //traverse list based on move direction
if(BUTTON_IsPressed(BUTTON_S3) | BUTTON_IsPressed(BUTTON_S4)){
break;
}
if(index == 5) {
direction = -1; //if all positions displayed, change direction
} else if (index == 0) { //if we went all the way to the left
direction = 1; //go right
}
}
}
Stack
I first divided my LEDs into two groups - one that is mounted on the stack baza
and one that will be 'moving'. To showcase the moving part I declared index
that will represent the currently moving LED. base_index
is the index of the far-left free bit (free meaning not turned on) and will change once a moving bit stops at that index.
We are displaying the mounted LEDs and the moving one - until all LEDs are on and the display reaches =255
.
void stack(){
int index = 0; // power of 2 (for "units")
int baza = 0; // value already on the end of the stack
int base_index = 7; // power of saved value
int display = 0;
while(display < 256){ //stop when stack is full = all LEDs on
display = baza + (1 << index); // "saved" on stack + moving
LATA = display;
delay(250);
if(BUTTON_IsPressed(BUTTON_S3) | BUTTON_IsPressed(BUTTON_S4)){
break;
}
index++; //"moving" piece on stack
if (index > base_index){ //if "moving" led is past his place
index = 0; //reset for next moving piece
baza = baza + (1 << base_index); //save value of saved led
base_index--; //place for next to save moved to the right
}
}
}
Pseudo Random Number Generator
I declared the first seed (in decimal) outside the function - each time we enter the program we will be starting with the first seed. The numbers and operations used are from the tutorial I mentioned above.
int seed = 115; //seed for first generation
void pseudo()
{
while(1){ //break if buttons=pressed
int m = pow(2, 32);
int a = 22695477; //random number
int new_num = (a * seed + 1) % m; //+see sources used
new_num &= 63; //convert to 6-bit
LATA = new_num; //display
if(BUTTON_IsPressed(BUTTON_S5)){ //if S5 - generate new
seed = new_num; //next num will be based on the previous num
new_num = (a * seed + 1) % m;
LATA = new_num;
}
delay(250);
if(BUTTON_IsPressed(BUTTON_S3) | BUTTON_IsPressed(BUTTON_S4)){
break;
}
}
}
Conclusion
Be on the lookout for the rest of my Introductory microcontroller tasks 😊