Home > electronics, programming > Simple Serial User Interface on PIC

Simple Serial User Interface on PIC

So today I needed to control some stuff on my PIC by using the terminal on my PC through RS-232 serial. I want to control the speed on 2 motors connected to the PIC, either separately or both of them together. To do that I divided the tasks that the User Interface (UI) had to provide. So from the main menu the user should be able to choose to control

  • Motor A
  • Motor B
  • Both Motors

In each of the sub-menus shown above the user should have some choices for acting on the motors. Before complicating this stuff more, I will show you the method I used to create this simple menu on my 18F2525 PIC. It doesn’t matter if you don’t have this PIC or even any other microcontroller. The concept is the same.

If you try to tackle the problem an if-then-else structure may seem like an easy solution but I can tell you it is going to messy pretty soon! We need a more clear, robust solution. But first let’s see what we need to do.

PIC User Interface Layout

The image pretty much explains it all. If we are at Main Menu the only valid keys are 1, 2 or 3. Each leads to a new sub menu. From there, there are again three choices 0 that takes us back to Main Menu and + or that will need to take an action (colored green). So if we implement this menu you will be able to implement more complex ones based on the same concept.

I got this idea based on Finite State Machine concept but its not quite right so we cannot call it like that! Anyway. Each of the menu item (Main Menu, Motor A, Motor B, Both Motors), is a different state in the program let assign them 0,1,2,3 accordingly. So if we are at state 0 we can go to state 1,2 or 3 with the right key pressed in the terminal. However if we are at state 1, we can only go back to state 0 or stay at the same state and complete some actions (forwards, backwards) with the right buttons pressed, once more.

So the way to implement this is by using switch/case. I think it will be much clearer if I show you the code. First let’s see how to we switch between the states.

switch (ss)	// Change state
{
	case 0:	// Main Menu
		if (ic==0x31) ss=1;
		if (ic==0x32) ss=2;
		if (ic==0x33) ss=3;
		break;
	case 1:	// Motor A
		if (ic==0x30) ss=0;
		break;
	case 2:	// Motor B
		if (ic==0x30) ss=0;
		break;
	case 3:	// Both Motors
		if (ic==0x30) ss=0;
		break;
}

There are some undefined stuff in there I know! Remember this is just the interesting part of the code. At the top you can see the ss variable. That is the variable holding the current state of the system i.e. at which menu we are currently are. This variable is initialized as 0 i.e. Main Menu.

There is another variable in there called ic which is actually the ascii code (read about ascii codes here) of the last key pressed in the terminal. 0x31 represents 1, ox32 represents 2 and so on. Compare the code with the figure and see how it matches the state transactions.

So there you have it. A nice tidy and robust way to navigate through menus. But we are not finished yet. Remember that we also need to take some actions like moving the motor forward and backwards. For that I created another switch/case branch that we will insert all the actions to be taken based on the state we are currently in (some key may have different operation in different states!) and of course the key pressed.

switch (ss)	// Act on state
{
	case 0:	// Main Menu
		mytext="Main Menu\r";
		break;
	case 1:	// Motor A
		mytext="Control M1\r";
		if (ic==0x2B) {move_motor_forwad(ma);}
		if (ic==0x2D) {move_motor_backwards(ma);}
		break;
	case 2: // Motor B
		mytext="Control M2\r";
		if (ic==0x2B) {move_motor_forwad(mb);}
		if (ic==0x2D) {move_motor_backwards(mb);}
		break;
	case 3: // Both Motors
		mytext="Control Both\r";
		if (ic==0x2B) {move_motor_forwad(ma);move_motor_forwad(mb);}
		if (ic==0x2D) {move_motor_backwards(ma);move_motor_backwards(mb);}
		break;
}

I think it is pretty clear what happens here. Let me just tell you that the variable mytext stores the text that it is sent to back to the terminal to indicate which menu the user is currently in.

So to complete this, include an infinite loop (or you can use interrupts, its up to you) to check if button was pressed in the terminal. Most probably you have the RS-232 hardware module of the PIC working. So we need to check if a new data is in. I use MikroC so this is done using the UART1_Data_Ready() command. If there is new data, then run the two branches of code we discussed above and have an output function to write the text on the monitor (I used UART1_Write_Text(mytext);).

As always your comments, questions and suggestions are welcome.


Related Posts:



  1. No comments yet.
  1. No trackbacks yet.