![]() |
Forum Index : Microcontroller and PC projects : Sample Code switch timer
Author | Message | ||||
atmega8![]() Guru ![]() Joined: 19/11/2013 Location: GermanyPosts: 724 |
Hi mmbasic Fan's, i would like to program a timer that can do some(3-5) switch cycles per day. It should be based on the internal time$ variable. Has someone please a code sample or a conceptual approach for this? I am a little bit stuck in my ideas;-((( THX, Dietmar |
||||
paceman Guru ![]() Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
You may be able to get some ideas from this. Time$ & Date$ have previously been set daily via a battery backed DS1307 real time clock chip using Jman's I2C code and there's a little Nokia 5110 LCD displaying time (updated each second) and status of the door. Also Time$ & Date$ are automatically reset if it powers down or there's a reset. Greg TimeOpen$ = "07:00:00" 'Door open & close times
TimeClose$ = "22:00:00" . . SETTICK 1000,Time_Update,1 'Update LCD time display each second SUB Time_Update PosX=36: PosY=1: LCD_GotoXY Text$ = TIME$ Lookup LCD_StringOut END SUB 'Main loop - Servo time checking TIMER = Secs_from_Midnight(TIME$)*1000 'Sync TIMER & real time AMopen = Secs_from_Midnight(TimeOpen$) *1000 PMclose = Secs_from_Midnight(TimeClose$) *1000 red = 9: green = 10 'LED pins: red=closed, green=open SETPIN red,DOUT: SETPIN green,DOUT PIN(red) =1: PIN(green) =1 'Turn both LEDs ON Status$ = "" SETTICK 5000,Check_Time,2 'Check door posn every five secs SETTICK 2000,Flash_LED,3 'Flash LEDs every two secs DO 'programs loops in here waiting for timer interrupts LOOP SUB Flash_LED IF Status$ = "IN ONLY" THEN PIN(red)=1: PIN(green)=0 IF Status$ = "OPEN" THEN PIN(red)=0: PIN(green)=1 PAUSE 100: PIN(red)=0: PIN(green)=0 'Flash LED for 0.1 secs END SUB SUB Check_Time Ti = TIMER 'Ti - variable to minimise TIMER calls IF Ti => 86400000 THEN TIMER = 1 'Reset TIMER at midnight IF Ti < AMopen THEN SERVO 2,50,2.1 Status$ = "IN ONLY" 'IN ONLY = closed ELSEIF Ti => AMopen AND Ti < PMclose THEN SERVO 2,50,1.4 Status$ = "OPEN" ELSEIF Ti => PMclose THEN SERVO 2,50,2.1 Status$ = "IN ONLY" ENDIF PosX=0: PosY=5: LCD_GotoXY 'display the door status Text$ = "----"+ Status$ +"----" Lookup LCD_Stringout END SUB FUNCTION Secs_from_Midnight(convert$) conv1 = VAL(MID$(convert$,1,2)) *3600 conv2 = VAL(MID$(convert$,4,2)) *60 conv3 = VAL(MID$(convert$,7,2)) Secs_from_Midnight = conv1 + conv2 + conv3 END FUNCTION '------------------------------------------ |
||||
viscomjim Guru ![]() Joined: 08/01/2014 Location: United StatesPosts: 925 |
Hi Atmega8, Here is a quick and dirty little program I use for the break and lunch time alert at my office / shop. No display as it sits in a closet, but you could easily add one. There are two relays that just pulse a buzzer in one of two locations... The shop and the office. The if time$ then statements are the times when I want them to buzz. Notice the subs use over 1 second delays therefore by the time it returns the time has changed. Like I said, quick and dirty, and has been working for a long long time. I am using the cheapo DS3231 I2C RTC to keep time and the uMite time is updated every hours. Recovers well after power failure. Hope this helps.... OPTION AUTORUN ON
SetPin 3, DOUT 'relay 1 SetPin 5, DOUT 'rekay 2 SETPIN 16, OOUT 'heartbeat led - just to show life Pin(3)=0 Pin(5)=0 PIN(16)=0 DIM RTCBUFF(7) SETMCLOCK SETTICK 3600000,SETMCLOCK,1 'update uMite clock every hour SETTICK 250, HEARTBEAT,3 Do IF TIME$ = "08:45:00" THEN SHOP 'pulse shop buzzer relay IF TIME$ = "09:00:00" THEN SHOP IF TIME$ = "12:30:00" THEN SHOP IF TIME$ = "13:00:00" THEN SHOP IF TIME$ = "14:00:00" THEN SHOP IF TIME$ = "14:15:00" THEN SHOP If Time$ = "08:15:00" THEN OFFICE 'pulse office buzzer relay LOOP SUB HEARTBEAT PULSE 16, 125 END SUB '********************************************** SUB OFFICE PULSE 5, 250 PAUSE 1050 END SUB '********************************************** SUB SHOP PULSE 3, 250 PAUSE 1050 END SUB '********************************************** SUB SETMCLOCK I2caddr = &h68 ' DS3231 I2C address I2C open 100,100 ' Enable I2C I2C write I2caddr, 0, 1, 0 I2C Read i2caddr, 0, 7, RTCbuff(0) ' Read Time I2C Close BCDTEMP = RTCBuff(0) BCDtoDec BCDTEMP SEC$ = Str$(decimal) BCDTEMP = RTCBuff(1) BCDtoDec BCDTEMP MIN$ = Str$(decimal) BCDTEMP = RTCBuff(2) BCDtoDec BCDTEMP HOURS$ = Str$(decimal) BCDTEMP = RTCBuff(3) BCDtoDec BCDTEMP DAYOFWEEK = decimal BCDTEMP = RTCBuff(4) BCDtoDec BCDTEMP DAY$ = Str$(decimal) bcdtemp = rtcbuff(5) BCDtoDec BCDTEMP MONTH$ = Str$(decimal) bcdtemp = rtcbuff(6) BCDtoDec BCDTEMP YEAR$ = Str$(decimal + 2000 ) T$ = HOURS$+":"+MIN$+":"+SEC$ D$ = DAY$+"/"+MONTH$+"/"+YEAR$ Time$ = T$ Date$ = D$ END SUB '********************************************** Sub BCDtoDec (BCDTEMP) Decimal = Fix(BCDTemp / 16) * 10 Decimal = Decimal + (BCDTEMP And &hF) End Sub '********************************************** SUB SETDS3231 ' SET DS3231 ' MMBasic Time$ and Date$ must be set first!!!!!!!! ' get seconds X = VAL(RIGHT$(TIME$, 2)) SECONDS = (X\10)*16 + X mod 10 ' get minutes X = VAL(MID$(TIME$, 4, 2)) MINUTES = (X\10)*16 + X mod 10 ' get hours X = VAL(LEFT$(TIME$, 2)) HOURS = (X\10)*16 + X mod 10 ' get day of month DD = VAL(LEFT$(DATE$, 2)) DOM = (DD\10)*16 + DD mod 10 ' get month MM = VAL(MID$(DATE$, 4, 2)) MONTH = (MM\10)*16 + MM mod 10 ' get year YY = VAL(RIGHT$(DATE$, 2)) YEAR = (YY\10)*16 + YY mod 10 ' get day of the week YYYY = VAL(RIGHT$(DATE$, 4)) A = (14-MM)\12 M = MM + 12*A - 2 Y = YYYY - A DOW = (DD + Y + Y\4 - Y\100 + Y\400 + 31*M\12) mod 7 + 1 I2C open 100,100 I2C write &H68, 0, 8, 0,SECONDS,MINUTES,HOURS,DOW,DOM,MONTH,YEAR If MM.I2C <> 0 then print "I2C error = "; MM.I2C end Endif I2C close END SUB |
||||
paceman Guru ![]() Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
Hi Jim, I've always assumed a PAUSE would halt SETTICK interrupts, but that can't be so if your code is working OK. Also have you ever noticed whether any of the set-points are missed, given that each is only valid for a second? Greg |
||||
viscomjim Guru ![]() Joined: 08/01/2014 Location: United StatesPosts: 925 |
Hi Paceman, so far this hasn't missed a beat for a long time. In the manual it says... "This process will run independently of the main program which could be doing something completely unrelated". I basically just made the assumption that the pause was "unrelated". I hope I didn't miss something here, but the unit does work every day. Maybe I just got lucky.... Edit... Now you got me curious. I will try and time how many times that do loop actually checks the time$ every second. I just assumed it would be quite a few times and that I wouldn't miss anything. Again, Lucky???? Next time I guess I could use a flag to see if the sub was called instead of wasting 1050ms. Kind of sloppy code, but it serves it purpose considering I had a very short period of time to make this. |
||||
paceman Guru ![]() Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
Well looks like I might have been unnecessarily complicating a few things if a PAUSE doesn't stop SETTICK interrupts, but then at what point is the program "re-PAUSED". Does it just execute the target interrupt routine and "re-PAUSE" when it returns via the IRETURN or when? What happens if another SETTICK command is within the first interrupt routine (probably pretty poor practice but...) What happens if another interrupt occurs during this same period? Hmmm.... If you see any lost alarms when you have a look at your code try assigning the first TIME$ call to a variable and then use that for the rest of the IF's to see if it makes a difference. Greg |
||||
atmega8![]() Guru ![]() Joined: 19/11/2013 Location: GermanyPosts: 724 |
Hello, thank you very much, for your fast response and help with your sample code. As we can see, this is not as trivial as one can think . Beside the question, if settick will be stoped by a pause or interrupts, i see another problem. Lets assume, we switch on a light at 8:00 and turn it off at 11:00. If we have a powerdown, reset or similar between this switchpoints, then we will will not get the correct state of the light ( depending on the signal logic / portstate). So we have to check for the state within an intervall of switchpoint, like " if time $ > 8:00 and < 11:00 then light on". It will get more complicated if we implement a dynamic number of switchpoints.. But this can not be done with the string variable time$, so we have to convert it to a number, which should be easy when we convert it to minutes from midnight........ Hope we will get a code that will be able to avoid all this problems. Maybe we can expand the code library with a sample programm for a switchtimer. THX |
||||
atmega8![]() Guru ![]() Joined: 19/11/2013 Location: GermanyPosts: 724 |
Aha... I see that pacemans code will do all the things i mentioned above. He converts to milliseconds since midnight and he decides based on intervall between switchpoints and not only on one point of time. Cool pacemann, this will help. THX, pacemann and visconjim ! |
||||
Geoffg![]() Guru ![]() Joined: 06/06/2011 Location: AustraliaPosts: 3282 |
Just to clarify, interrupts will continue to occur even inside a pause. Other delays associated with hardware (such as DS18B20()) do block interrupts. A subtle distinction. Geoff Geoff Graham - http://geoffg.net |
||||
paceman Guru ![]() Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
Hi Geoff, How 'far' do they execute? Do they effectively 'turn off' a PAUSE that's been turned 'on' in the main program or do they only execute to the end of the interrupt routine? Greg |
||||
Geoffg![]() Guru ![]() Joined: 06/06/2011 Location: AustraliaPosts: 3282 |
Wow, that question reads like a foreign language and don't understand any of it. The pause command constantly checks for an interrupt condition and if one has occurred it will execute the interrupt routine. On return from the interrupt the pause commend will continue with the pause but any time spent in the interrupt routine will be subtracted from the pause time so that the pause would be the same with or without the interrupt. You can also use pause in an interrupt routine although that cannot be interrupted because you are already in an interrupt. Did that answer the question? Geoff Geoff Graham - http://geoffg.net |
||||
viscomjim Guru ![]() Joined: 08/01/2014 Location: United StatesPosts: 925 |
Maybe that explains why my somewhat cheezy program runs ok. I really like the way interrupts were set up and how they work. They come in quite handy. |
||||
paceman Guru ![]() Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
That answers it perfectly thanks Geoff. Greg |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |