PIC16F54 Buzzer will not turn off - Page 1
Forum section: electronics / general

author: Aztlanpz
author_rank: Regular Contributor
timestamp: January 18, 2020, 01:41:30 am
content: Code:;************************************************************; written by: XXXXXXXXX*; date: 1/14/2020*; version: 1.0*; file saved as: LED_Buzzer.asm*; for PIC16F54*; clock frequency: 2.4576 MHz*;***********************************************************; PROGRAM FUNCTION: Turns on an LED on PoartA, and a Buzzer;on PortB;___________________________________________________________#Include <p16f54.inc>__CONFIG _OSC_XT & _WDT_OFF & _CP_OFF;===========================================================; Declarations:portaequ05portbequ06Mark30equ07Post80equ08_5Second equ09org1FFhgotoStartorg0;==========================================================; Subroutines:Initmovlwb'00000111';set up TMR0 to countoption;internally, prescaled by 256clrfPORTA; resets input/output portsclrfPORTBmovlwb'00000'; sets up which pins are inputstrisPORTA; and which are outputsmovlwb'00000000'trisPORTBretlw0;=========================================================; Program Start:StartcallInitmovlwd'30';moves the decimal number 30 intomovwfMark30;the GPF called Mark30, the markermovlwd'80';moves the decimal number 80 intomovwfPost80;the GPF called Post80, the first;postcalermovlwd'5';move the decimal number 5 intomovwf_5Second;the GPF called _5SecondTimeLoopmovfwMark30;takes the number out of Mark30subwfTMR0,w;subtracts this number from the;number in TMR0, leaving the result;in the working register (and leaving;TMR0 unchanged)btfssSTATUS,Z;test the zero flag-skip if set,i.e. if;the result is zero it will skip the next;instructiongotoTimeLoop;if the result isn't zero, it loops back to;'TimeLoop'movlwd'30';moves the decimal number 30 intoaddwfMark30,f;the working register and then;adds it to Mark30decfszPost80,f;decrements Post80, and skips the next;instruction if the result is zerogotoTimeLoop;if the result isn't zero, it loops back to;'TimeLoop';When it reaches this point, 1 second;has passedmovlwd'80';resets Post80, moving the number 80movwfPost80;back into itcallLEDTogglebcfPORTB,RB0;turns buzzer ofdecfsz_5Second,f;check if 5 seconds have pass and turns on;BuzzercallTurnBuzzergotoTimeLoopTurnBuzzerbsfPORTB,RB0;turns buzzer onmovlwd'5';move the decimal number 5 intomovwf_5Second;the GPF called _5Secondretlw0x00LEDTogglemovfPORTA,w;Move PORTA to the working registerxorlwb'0001';Toggle bit RA0 from PORTAmovwfPORTA;retlw0x00ENDI wrote a program in assembly to blink and LED on PortA bit0 every second and to turn on a buzzer. On PortB, bit0 beeps every 5 seconds nut once the buzzer activates it will produce a continuous tone.

author: cv007
author_rank: Frequent Contributor
timestamp: January 18, 2020, 04:20:29 pm
content: Without going through the trouble of trying to read asm, even though should be simple, I would guess you are not taking into account timer0 will be at a certain number for 256 clocks so are probably getting messed up at that point.I'll suggest something that you may not want to do, but why not just take advantage of the xc8 compiler. You get something everyone can read so help is easier to come by, you can get it right quicker, and it produces roughly the same size code. In this case you can even use a delay instead of the timer if wanted.This compiles to around ~68 'words' (13% of flash), which is probably not too far from what you have now-#include <xc.h>#include <stdint.h>#define _XTAL_FREQ 2457600void led_on(){ RB0 = 1; }void led_off(){ RB0 = 0; }void led_tog(){ RB0 = !RB0; }void buzzer_on(){ RA0 = 1; }void buzzer_off(){ RA0 = 0; }void init(){TRISA=0;TRISB=0;led_off();buzzer_off();OPTION=7; //timer0 prescale 256}//void delay_ms(uint16_t ms){ for( ; ms--; __delay_ms(1) ); }void wait_1s(){//_XTAL_FREQ/prescale = overflows needed for 1s = 9600for(uint16_t i = 0; ; ){while( TMR0 != 0 ); //wait for 0if( ++i >= 9600 ) return; //done?while( TMR0 == 0 ); //wait for NOT 0}}void main(void) {init();for(uint8_t i = 0; ; ){//delay_ms(1000);wait_1s();led_tog();buzzer_off();if( ++i >= 5 ){buzzer_on();i = 0;}}}

author: KL27x
author_rank: Super Contributor
timestamp: January 20, 2020, 06:09:10 pm
content: The nice feature of assembly is that you can insert break points or flags in your code to figure out what is happening.You have done a lot of unconventional (read weird) things with your code. I think you have already gotten too far along without verifying. Your one second timing code is not readily apparent. It 80 cycles of 30 clicks of the timer equal to one second?The conventional way do do this would be to check the timer when it reaches your mark (of say 30); when it does, you increment another counter/postscaler if necessry AND you set the timer register back to 0. The way you letting the timer roll and then incrementing the mark 30 register by 30 is just weird. This wraps beyond 256, of course, which should be fine if the timer is 8 bit; but this is weird. And you can't do a carry check with this method, because of the eventual wrap around.Also, it's possibly fine in this exact case that you are doing subtractions and zero checks on the timer. But in general, you ought to do carry checks, which will be more full proof, in case the code loop does not execute fast enough to catch the timer on that particular tick. As your code gets more complex, with more potential branch possibilities, this will be harder to determine.Your chief complaint is that the buzzer does not turn off. So I assume you are getting your one second intervals good enough.The initialization subroutine is only called once. The only other place that turns off the buzzer is part two of your Timeloop. You might want to place some test code there to see if this ever gets executed beyond the first time.Another part that appears strange is :;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;decfsz _5Second,f ;check if 5 seconds have pass and turns on;Buzzercall TurnBuzzergoto Timeloop;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;I dunno. Maybe this is as intended, but it appears your logic is backwards. But maybe I don't understand what you're doing, here with the 5 second timer.

author: KL27x
author_rank: Super Contributor
timestamp: January 21, 2020, 09:40:35 am
content: Thanks to insomnia, I looked again at your code.I am assuming that:1. Using your external clock, that 30 ticks of tmr0 is about an 80th of a second; I assume that part is working the way you intended.2. Your buzzer turns on after 1 second of run time and does not turn off.3. Your LED first turs on at this exact same time, at 1 second. And that it continues to toggle on/off every 1 second, thereafter. But the buzzer does not turn off.4. I further assume you intended the buzzer to turn on at 5 seconds and to remain on for 1 second.If all of this is correct, then what I copied/highlighted in my first post is surely your problem. You just had dyslexia on your skip if instruction. The first time the 1 second time gate was reached, the LED toggled, the buzzer pin was cleared, but the Buzzer subroutine got called 2 instructions later (which was not your intention). The Buzzer subroutine resets the 5-second register, so this result is always the case every subsequent time the 1 second gate is passed.Code: call LEDTogglebcf PORTB,RB0 ;turns buzzer of;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; decfsz _5Second,f ;check if 5 seconds have pass and turns on;Buzzer;_____________________________________________________decf _5second,fbtfsc STATUS,Z ; skip the next instruction if the result is NOT zero;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;call TurnBuzzergoto TimeLoopYou could also do this:decfsz _5second,fgoto TimeLoopcall TurnBuzzergoto TimeLoopThe buzzer should turn on at 5, turn off at 6, turn on at 10 turn off at 11.RB0 should have a square wave 20% duty cycle with 5 second period, on for 1, off for 4. This is in exclusion of the first-run after reset. It should remain digital output low for the first 5 seconds.RA0 should have a square wave of 50% duty cycle with 2 second period. It should start as digital output low for the first second, then first switch to output hi at exactly 1 second.