Blog 3 | RTOS | Kuba
These last two weeks started with us becoming familiar with how the example9 (basic kernal) code from the previous two weeks works. This included looking at the serial interrupt task, which waits for input to be typed in the terminal. This code also includes two other tasks: "The_first_rtos_task" and "The second_rtos_task". Both of these tasks toggle an LED at different rates, and print a message "Task X LED On/Off". The final task is the kernal itself. This task waits for one of the four possible inputs : "enable1", "enable2", "disable1", and "disable2". All of these inputs either enable or disable one of the two previously mentioned tasks.
The first aim of the work to be done this week was to work with our partner, Tao in my case, to iterate on this kernal example and add input and output tasks as well as a state machine task that controls the outputs depending on the inputs and the current state. State machines were explained more in the first blog. The first step in this process was the creation of a state machine state diagram to show what functionality we want to implement. We decided on two inputs, a button, as well as a counter which when it reaches 10 acts as an input. At this point we weren't aware of using the ADC input from the potentiometer as an input, which would replace the counter input looking back now. The state diagram for the state machine is shown below.
The next step was deciding the structure of the code, in terms of the number of tasks and how they interact. It was chosen to have a kernal task that can independently enable or disable the two outputs. There are also two input tasks, which send messages when the input is activated. There are two output tasks which make the outputs happen when they receive a message. The heart of the code is the FSM task. This task jumps between states S0, S1, and S2. The inputs are messages in its queue from the input tasks. Depending on the state and the input the FSM then jumps to a different state and chooses an output. The output is a message sent to the output tasks. A diagram of the code is shown below.The implementation began with me working on the FSM and Tao working on the output tasks. The FSM task first polls to see if it has any messages and if so reads it into the state_input variable. What follows is an if - else if - else ladder for each state, with another if - else if inside each state for each input. Then the FSM sends messages to the output tasks depending on the state and inputs. I also then implemented the input tasks. Initially the tasks were two seperate counters that sent an input when reaching a certain number, 10 and 15 respectively in this case. After we received example code on how to use the button as input, one of the counter inputs was changed to a button input. As mentioned earlier we didn't notice the ADC input option, so that could be a future improvement for the other input. Tao wrote the two output tasks. One of the tasks wrote "LED On" to the LCD, which happened after the counter reached 10, and the other wrote "LED Off", after the button was pressed. The FSM also printed messages to the terminal indicating state transitions to have a visual confirmation of states changing. As well as that we are printing the count as it increments and a message once it reaches 10, to see if the LCD changing matches up with the count as intended. The final code is shown below:
#include <16f877a.h>
#use delay(clock=20000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#use rtos(timer=1,minor_cycle=100ms)
#include <stdio.h>
#include <stdlib.h>
#include "BENGLCD420.C"
#define BTN PIN_A4
#define RED PIN_B5
#define GREEN PIN_A5
#define s0 1
#define s1 2
#define s2 3
#define input1 1
#define input2 2
#define output1 1
#define output2 2
#include <string.h>
// this character array will be used to take input from the prompt
char input [ 30 ];
// this will hold the current position in the array
int index;
// this will signal to the kernal that input is ready to be processed
int1 input_ready;
int8 count1;
int8 state_input = 0;
int8 state;
// different commands
char en1 [ ] = "enable1";
char en2 [ ] = "enable2";
char dis1 [ ] = "disable1";
char dis2 [ ] = "disable2";
#task(rate=500ms,max=100ms)
void input1_task();
#task(rate=500ms,max=100ms)
void input2_task();
#task(rate=100ms,max=100ms,queue=1)
void output_task1();
#task(rate=100ms,max=100ms,queue=1)
void output_task2();
#task(rate=100ms,max=100ms,queue=1)
void FSM_task ( );
#task(rate=500ms,max=100ms)
void The_kernal ( );
// serial interupt
#int_rda
void serial_interrupt ( )
{
if(index<29) {
input [ index ] = getc ( ); // get the value in the serial recieve reg
putc ( input [ index ] ); // display it on the screen
if(input[index]==0x0d){ // if the input was enter
putc('\n');
input [ index ] = '\0'; // add the null character
input_ready=TRUE; // set the input read variable to true
index=0; // and reset the index
}
else if (input[index]==0x08){
if ( index > 1 ) {
putc(' ');
putc(0x08);
index-=2;
}
}
index++;
}
else {
putc ( '\n' );
putc ( '\r' );
input [ index ] = '\0';
index = 0;
input_ready = TRUE;
}
}
void input1_task(){
if(count1 == 10){
printf("Count reached 10\n\r");
count1 = 0;
rtos_msg_send(FSM_task, input1);
}
else{
count1 = count1 + 1;
printf("Count = %i \n\r", count1);
rtos_msg_send(FSM_task, 0);
}
}
void input2_task(){
if(!input(PIN_A4)){
rtos_msg_send(FSM_task, input2);
}
else{
rtos_msg_send(FSM_task, 0);
}
}
void output_task1(){
if(rtos_msg_poll()>0){
if(rtos_msg_read() == output1){
lcd_gotoxy(1,2);
printf(lcd_putc, "LED ON (cnt=10) ");
}
}
}
void output_task2(){
if(rtos_msg_poll()>0){
if(rtos_msg_read() == output2){
lcd_gotoxy(1,2);
printf(lcd_putc, "LED OFF (button)");
}
}
}
void FSM_task(){
if(rtos_msg_poll()>0){
state_input = rtos_msg_read();
}
if(state == s0){
lcd_gotoxy(1,2);
printf(lcd_putc, "In IDLE state");
if(state_input == input1){
rtos_msg_send(output_task1, output1);
printf("s0 -> s1\n\r");
state = s1;
}
else if(state_input == input2){
rtos_msg_send(output_task2, output2);
printf("s0 -> s2\n\r");
state = s2;
}
}
else if(state == s1){
if(state_input == input1){
rtos_msg_send(output_task1, output1);
printf("s1 -> s1\n\r");
state = s1;
}
else if(state_input == input2){
rtos_msg_send(output_task2, output2);
printf("s1 -> s2\n\r");
state = s2;
}
}
else if(state == s2){
if(state_input == input1){
rtos_msg_send(output_task1, output1);
printf("s2 -> s1\n\r");
state = s1;
}
else if(state_input == input2){
rtos_msg_send(output_task2, output2);
printf("s2 -> s2\n\r");
state = s2;
}
}
}
void The_kernal ( ) {
while ( TRUE ) {
printf ( "INPUT:> " );
while(!input_ready)
rtos_yield ( );
printf ( "%S\n\r%S\n\r", input , en1 );
if ( !strcmp( input , en1 ) )
rtos_enable ( output_task1 );
else if ( !strcmp( input , en2 ) )
rtos_enable ( output_task2 );
else if ( !strcmp( input , dis1 ) )
rtos_disable ( output_task1 );
else if ( !strcmp ( input , dis2 ) )
rtos_disable ( output_task2 );
else
printf ( "Error: unknown command\n\r" );
input_ready=FALSE;
index=0;
}
}
void main ( ) {
// initialize input variables
index=0;
input_ready=FALSE;
// initialize interrupts
enable_interrupts(int_rda);
enable_interrupts(global);
//init lcd
lcd_init();
state = s0;
count1 = 0;
count2 = 0;
SET_TRIS_B(0x00);
SET_TRIS_a(0xDF);
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(AN0);
set_adc_channel(0);
rtos_run();
}


Comments
Post a Comment