Maker Pro
Maker Pro

Project at school

Hello :). I'm new to these forums and new to PIC programming. We haven't been taught anything about PIC programming thus far at school, so I'd like some advice.
I'm making a sort of novelty egg timer. It involves a wooden automata popping out of the base of the product when the time is up and starting a "Rube Goldberg" like chain reaction resulting in a bell being hit. I have several questions though.
  1. Can PIC chips time for long periods of time up to, say, an hour? When doing a mock program earlier I found you can't use "wait" for more than 65 seconds...?
  2. I want to use four buttons to set the time: +1 minute, -1 minute, +10 minutes and -10 minutes. How should I write the program in order for these buttons to add up the time?
  3. I would like to use an LCD display to show how much time has been entered. What extra programming will be involved?
  4. Taking all of this into account, what PIC chip would be best? I need two outputs for the motor but I don't know how many I need for the LCD display. I know I also need 4 inputs

Thanks for any help.:D

PandaMan
 

(*steve*)

¡sǝpodᴉʇuɐ ǝɥʇ ɹɐǝɥd
Moderator
Are you using a PIC, or a PICaxe?

1) You can have longer waits by placing a wait of (say 60 seconds) inside a loop that executes 60 times. Bingo -- 1 hour delay.

2) you need a counter for the number of minutes and at each press of a button increment or decrement it appropriately. Remember to debounce the button and not to decrement below zero or above the max count for the counter (or the max time you want the timer to time to)

3) Lots. However if you use a PICaxe they have built in interfaces to some displays. If not, you may be able to find code that does it already. Interfaces can require between 2 and 8 I/O pins.

4) You need to determine how many inputs and outputs you need, and how big your program is going to be. You also need a chip that has the appropriate devices on it (You don't need much I expect). There are about three bazillion different PIC chips, find something easily available with plenty of IO and memory. Internal clock is always good too. If you go PICaxe, there are fewer options so the choice becomes easier :)

edit: Excess I/O and memory is so much better than I/O pins and memory you don't have.
 
Last edited:
I was thinking of using a PICaxe 14M2, however if I want the LCD display it would probably be best to use a 20M2? That would definitely have enough memory for my program and I think there are enough pins.
How many pins will this LCD need? http://www.picaxe.com/Hardware/Add-on-Modules/Budget-Serial-LCD-Module/

What's involved in creating a counter? Is there a special function or do I use a variable? The way I was trying to do it before was to change a variable (say w0) by differing amounts depending on the button pressed, then when another is pressed to start the timer I used "sleep w0". The only thing I can think of about that is that I don't know how to add values onto a variable...?

So if I used a 20M PICaxe, I would have 5 inputs, which would leave me with 13 outputs, right?

PandaMan
 
This is my code so far but I'm stuck. Could anyone help?

Code:
let b0 = 0
main:
	if pin1=1 then
		let b0 = b0+1
		endif
	if pin2=1 then
		let b0 = b0-1
		endif
	if pin3=1 then
		let b0 = b0+10
		endif
	if pin4=1 then
		let b0 = b0-10
		endif
	if pin0=0 then
		goto main
	elseif pin0=1 then
		goto function
		endif

function:
		wait 60
............

And that's where I'm stuck. How do I make the "function" code loop?
Is it something to do with the "do...loop" command?
 
Last edited:

(*steve*)

¡sǝpodᴉʇuɐ ǝɥʇ ɹɐǝɥd
Moderator
You need to do a lot more than that.

You need to learn what debouncing means.

If those various pins are your buttons, then you probably want to only count up when the button is pressed, not while the button is pressed.

check out the "For" command. it lets you do things more than once...

The PICaxe forum may be able to help you with interfacing to an LCD module.
 
Ah ok. So to make the loop I need to do this?
Code:
function:
		[B]for b0 = 0 to b0
		wait 60
		next[/B]
		let b0 = 0 
		goto main

I had thought about that problem with the buttons. I've read about debouncing. So how do I actually do it?
 
Last edited:

(*steve*)

¡sǝpodᴉʇuɐ ǝɥʇ ɹɐǝɥd
Moderator
That looks better, but consider, do you want to start from 0?

Also, do you want to do something when the time expires?

To debounce in software you read the button twice (or more) with a small delay between the reads. You ignore the state of the button if those reads are different.

Once you have a debounced read of the button you need to compare the value to the last read. If it has changed you may need to take action (but maybe you don't). Lastly you remember this as the last read.

If you get 2 readings of the button that are the same,
 
That looks better, but consider, do you want to start from 0?

Also, do you want to do something when the time expires?

To debounce in software you read the button twice (or more) with a small delay between the reads. You ignore the state of the button if those reads are different.

Once you have a debounced read of the button you need to compare the value to the last read. If it has changed you may need to take action (but maybe you don't). Lastly you remember this as the last read.

If you get 2 readings of the button that are the same,

Okay. I spent all lunch at school today working the programming out and from what I gather it is working perfectly. Yes, you're right I didn't want to start from 0.

Yes, after the time expires there is a motor that will activate. I spoke to my teacher today and he said proper debouncing wouldn't be necessary, especially seeing as it's only a GCSE project.
Here is the updated code. All I need now is the LCD programming.
Code:
let b0 = 0
main:
	if pin1=1 then
		let b0 = b0+1
		endif
		pause 100
	if pin2=1 then
		let b0 = b0-1
		endif
		pause 100
	if pin3=1 then
		let b0 = b0+10
		endif
		pause 100
	if pin4=1 then
		let b0 = b0-10
		endif
		pause 100
	if pin0=0 then
		pause 100
		goto main
	elseif pin0=1 then
		goto function
		endif

function:
		if b0 = 0 then main
		for b1 = 1 to b0
		wait 1
		next
		high B.0
		pause 700
		low B.0
		high B.1
		pause 700
		low B.1
		let b0 = 0 
		goto main
 
Last edited:

(*steve*)

¡sǝpodᴉʇuɐ ǝɥʇ ɹɐǝɥd
Moderator
Yeah, that looks workable.

It's not the best way to debounce switches, but it will probably work acceptably since it's not like you're going to manufacture this as a product :)

I note you initialise b0 to 0, it is also good practice to initialise the states of the pins you're going to use (even if the default values are OK). It is also a good place to add comments, such as:

b0 = 0 ' The number of seconds the timer will pause for.

Your next task (should you decide to accept it) is to display the timer value on an LCD display.
 
Your next task (should you decide to accept it) is to display the timer value on an LCD display.

I've decided I'm going to go with an OLED display because I think they look cooler :p. And they have a lower power consumption, which would be wise if the timer could time for up to an hour (or even more).

It would be simpler to use an OLED display that has a slave chip, because then I can just use the 'serout' command, right? And what else is involved with 'serout', as in other necessary code?

Thanks,

PandaMan
 
Here is my complete code. It has the OLED display coded in, as well as a beep on every button press and the timer makes the OLED display count down. Let me know what you think :)
Code:
init:
	pause 500					;for OLED display to initialise
	let b0 = 0				;makes sure the counter variable is at 0
	serout B.2, N2400, (254,1)
	serout B.2, N2400, (#b0)
main:
	if pin1=1 then
		let b0 = b0+1
		serout B.2, N2400, (254,1)
		pause 30
		high B.3
		pause 50
		low B.3
		serout B.2, N2400, (#b0)
		endif
		pause 100
	if pin2=1 then
		let b0 = b0-1
		serout B.2, N2400, (254,1)
		pause 30
		high B.3
		pause 50
		low B.3
		serout B.2, N2400, (#b0)
		endif
		pause 100
	if pin3=1 then
		let b0 = b0+10
		serout B.2, N2400, (254,1)
		pause 30
		high B.3
		pause 50
		low B.3
		serout B.2, N2400, (#b0)
		endif
		pause 100
	if pin4=1 then
		let b0 = b0-10
		serout B.2, N2400, (254,1)
		pause 30
		high B.3
		pause 50
		low B.3
		serout B.2, N2400, (#b0)
		endif
		pause 100
	if pin0=0 then
		pause 100
		goto main
	elseif pin0=1 then
		high B.3
		pause 50
		low B.3
		goto function
		endif
function:
		if b0 = 0 then main
		for b1 = 1 to b0
		wait 3
		let b0 = b0-1
		serout B.2, N2400, (254,1)
		pause 30
		serout B.2, N2400, (#b0)
		next
		serout B.2, N2400, (254,1)	;Clears the display
		pause 30
		serout B.2, N2400, ("Time's Up")
		high B.0					;motor activates in one direction
		pause 700
		low B.0					;de-activate motor
		wait 1					;wait for the chain reaction to start					
		high B.1					;activate motor in opposite direction
		pause 700
		low B.1					;deactivates motor
		let b0 = 0				;resets b0
		serout B.2, N2400, (254,1)
		pause 30
		serout B.2, N2400, (#b0) 				
		goto main
 

(*steve*)

¡sǝpodᴉʇuɐ ǝɥʇ ɹɐǝɥd
Moderator
Does it work?

If so, great!

Good programming practice is to have the ENDIF lined up under the IF, and therfore the various pauses lined up under the IFs.

Once you do that the fact that the various "pause 100" commands always execute will be obvious. You need to comment these and say why -- it's not obvious. Maybe the next person who works on this code won't understand (or perhaps the person who assesses your work won't either).

It would also be good practice to note in your code (via comments) what the purpose and connection of all the variables and pins are.

Even better,

symbol SECPLUS pin1 ' pin 1 is the "add a second" pin
symbol OLED B.2 ' B.2 is the serial connection to the OLED display.
symbol SECONDS b0 ' b0 holds the number of seconds to delay

and then you can code

let SECONDS = 0

if SECPLUS = 1 then
let SECONDS = SECONDS + 1
serout OLED, N2400, (254,1)
... etc

As I've said before, our initialization section should also set the states of all the other pins you're using. Start off by making sure that the motor and buzzer are off! It's also good practice to set the directions of pins that are I/O pins. Even if you're using the default it serves to document what you're using. If someone ever tries to run the same code on a different PICaxe the same defaults may not apply.

(I'm speaking from over 30 years of commercial experience here -- I'm not making this up)
 
Ok that does seem logical. Thanks for the advice. I'll get on with that. :)

nfortunately, this is all in theory so far.I've only just started the project and haven't got the PCB printed and I haven't bought the materials yet. It works in the simulation. :p
 
Top