Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

40kHz Square wave from PIC16F819...

Status
Not open for further replies.

pixelsnpings

New Member
Hey.

Im using a PIC16F819 with the timer interrupt and prescaler to send a 40kHz square wave out PORTB (just simply inverting the entire register 80000 times a second.)

I set the prescaler to 128, and put a pre-start value of 27 in the TMR0 register.

But when I actually test the chip in my circuit the LED only blinks 1-2x per second. (used red LED for Test)

can anyone tell me why this might be happening? I've looked over the datasheet for this PIC and I thaught the PIC might be factory calibrated for 31kHz clock speed.

I tryed setting the clock peed myself and still had no success.

:confused:
 
Heres the code

Code:
;   This file is a basic code template for assembly code generation   *
;   on the PIC16F819. This file contains the basic code               *
;   building blocks to build upon.                                    *
;                                                                     *
;   If interrupts are not used all code presented between the ORG     *
;   0x004 directive and the label main can be removed. In addition    *
;   the variable assignments for 'w_temp' and 'status_temp' can       *
;   be removed.                                                       *
;                                                                     *
;   Refer to the MPASM User's Guide for additional information on     *
;   features of the assembler (Document DS33014).                     *
;                                                                     *
;   Refer to the respective PIC data sheet for additional            *
;   information on the instruction set.                               *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Filename:	    xxx.asm                                           *
;    Date:                                                            *
;    File Version:                                                    *
;                                                                     *
;    Author:                                                          *
;    Company:                                                         *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required:                                                  *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;                                                                     *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************

	list      p=16f819           ; list directive to define processor
	#include <E:\Program Files\Microchip\MPASM Suite\p16F819.inc>        ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file

	__CONFIG   _CP_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _CCP1_RB2 & _DEBUG_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_IO

; '__CONFIG' directive is used to embed configuration word within .asm file.
; The lables following the directive are located in the respective .inc file.
; See data sheet for additional information on configuration word settings.




;***** VARIABLE DEFINITIONS
w_temp        EQU     0x7E        ; variable used for context saving 
status_temp   EQU     0x7F        ; variable used for context saving





;**********************************************************************
	ORG     0x000             ; processor reset vector
	goto    main              ; go to beginning of program
	

	ORG     0x004             ; interrupt vector location
	movwf   w_temp            ; save off current W register contents
	movf	STATUS,w          ; move status register into W register
	movwf	status_temp       ; save off contents of STATUS register


; isr code can go here or be located as a call subroutine elsewhere
	btfss	INTCON, TMR0IF	;TMR0IF is set when the timer interrupt is called
	goto skp1
	

	comf PORTB, 1
	;BANKSEL PORTA
	;btfss PORTA, 2
	;goto SETP
	;bcf PORTA, 2
	;goto skp1
;SETP
	;bsf PORTA, 2
skp1
	BANKSEL TMR0
	movlw 8 ;we actually need the prescale to be 100 so we subtract 27 from the count down
	movwf TMR0
	bcf INTCON, TMR0IF ;we must clear this flag for interrupts and program to run properly



	movf    status_temp,w     ; retrieve copy of STATUS register
	movwf	STATUS            ; restore pre-isr STATUS register contents
	swapf   w_temp,f
	swapf   w_temp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt


main
	;Setup the I/O Pins
	call SetupOscillator
	call SetupPortA
	call SetupPortB
	call SetupTimerInterrupt


; remaining code goes here
	
Live
	btfss PORTA, 0
	goto skp

	bsf PORTA, 1

	goto Live
skp

	bcf PORTA, 1

	goto Live




SetupOscillator
	movlw b'01110000'
	movwf OSCCON
	return

SetupPortA
	BANKSEL PORTA 
	CLRF PORTA 

	BANKSEL ADCON1 
	MOVLW 0x06 ;All pins on port A are outputs
	MOVWF ADCON1
	MOVLW b'00000001'

	MOVWF TRISA
	return

SetupPortB
	BANKSEL PORTB
	CLRF PORTB 

	MOVLW 0x00
	BANKSEL TRISB
	MOVWF TRISB
	return

SetupTimerInterrupt
	CLRWDT 
	BANKSEL OPTION_REG 
	MOVLW b'10000100' ;Use Prescale value of 128, Internal Oscillator
	MOVWF OPTION_REG 

	BANKSEL TMR0
	movlw 8 ;we actually need the prescale to be 100 so we subtract 27 from the count down
	movwf TMR0

	;enable the interrupts
	bsf INTCON, TMR0IE
	bsf INTCON, GIE
	return

; initialize eeprom locations

	ORG	0x2100
	DE	0x00, 0x01, 0x02, 0x03


	END                       ; directive 'end of program'
 
The first error I spotted was OSCCON is in bank 1.

Once you correct OSCCON then your internal oscillator will be running at 8MHZ. To get a interrupt at 80KHz you need to interrupt every 25 cycles (8,000,000/4/80,000. To do this you need the prescaler to be 1 (assign it to the WDT) and load TMR0 with 256-25+latency. In order to interrupt this fast you need a very short interrupt service routine.

If you change your interrupt to,
Code:
	movwf   w_temp            ; save off current W register contents
	movf	STATUS,w          ; move status register into W register
	movwf	status_temp       ; save off contents of STATUS register
	movlw	.256-.25+9
	movwf	TMR0
	comf	PORTB, 1
	bcf	INTCON,TMR0IF ;we must clear this flag for interrupts and program to run properly
	movf    status_temp,w     ; retrieve copy of STATUS register
	movwf	STATUS            ; restore pre-isr STATUS register contents
	swapf   w_temp,f
	swapf   w_temp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt
then you will still be using 76% of the processor time just servicing the interrupt. Have you considered using the PWM module.

FYI, the latency value is the number of instructions in the ISR before the write to TMR0 + 2 for the interrupt latency + 2 for the Timer0 latency.

HTH

Mike.
 
Please note that you can experience a 1 cycle jitter on entering the interrupt if the interrupt occurs during a 2 cycle instruction. For this reason most of the Gurus recommend forgetting the "fudge factor" and suggest adding your computed value to the TMR0 register (including 2 counts for the new value to take effect).

As Mike (Pommie) suggested, you might consider using the PWM module to perform this task in the background and without jitter.

Mike
 
Using tmr2 would be a better solution than tmr0, tmr0 is really a pretty crappy timer, presumably only included these days for legacy reasons?.

However, he's never mentioned what he's trying to do, so it's hard to know what would be the best method?.
 
Nigel, I thought the title of the thread pretty well explained that the OP is wanting to generate a 40khz square wave?
 
Last edited:
Mike said:
Please note that you can experience a 1 cycle jitter on entering the interrupt if the interrupt occurs during a 2 cycle instruction. For this reason most of the Gurus recommend forgetting the "fudge factor" and suggest adding your computed value to the TMR0 register (including 2 counts for the new value to take effect).
Mike,
I have tried this in the past and I still get the jitter (at least in the simulator). Do you have example code that is jitter free? Or, confirmation that the simulator is wrong. :eek:


A rather interesting way to speed up the above ISR is to NOT save status and only use instructions that don't affect it.
Code:
	movwf   w_temp            ; save off current W register contents
	bcf	INTCON,TMR0IF     ;we must clear this flag for interrupts and program to run properly
	movlw	.256-.25+7
	movwf	TMR0
	btfss	PORTB,0
	goto	Setit
	bcf	PORTB,0
	swapf   w_temp,f
	swapf   w_temp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt

Setit	bsf	PORTB,0
	swapf   w_temp,f
	swapf   w_temp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt

Just academic really as it only saves 1½ cycles per interrupt. But interesting all the same.

Mike.
 
Hi Mike,

I can't really confirm it. Sorry. I don't have a scope and I'm not sure how to simulate interrupts. I have used it in code though for bit-banged 9600 baud serial I/O on a 12F675;

Code:
;
;  clear TMR0 interrupt flag, prep TMR0 for next interrupt
;
ISR_SET bcf     INTCON,T0IF     ; clear TMR0 interrupt flag       |B0
        movlw   -d'104'+2       ; setup for next 104-usec int     |B0
        addwf   TMR0,f          ;                                 |B0
 
I just tried it again in the simulator and it works correctly. It was out by one cycle and so I had to correct it with,
Code:
	movlw	.256-.25+2+1
	addwf	TMR0,F

I guess when I tried it in the past I must have done something wrong.

Mike.
 
Sceadwian said:
Nigel, I thought the title of the thread pretty well explained that the OP is wanting to generate a 40khz square wave?

But it didn't explain why! - or if it's continuous, or if it's pulsed, or if the processor needs to do anything else - it was really pretty vague!.
 
Knowing how almost all projects are module, even the one's in most people head's when a specific question is asked such as how do you create a square wave on a given chip the best answer is always to give them the one that produces said square wave and let THEM figure out for themselves why such a method might be right or wrong for their application. Otherwise you're going to end up hand feeding them everything, that's already dont enough around here.. The more questions you ask sometimes the more answers you have to give.
 
Sceadwian said:
Knowing how almost all projects are module, even the one's in most people head's when a specific question is asked such as how do you create a square wave on a given chip the best answer is always to give them the one that produces said square wave and let THEM figure out for themselves why such a method might be right or wrong for their application. Otherwise you're going to end up hand feeding them everything, that's already dont enough around here.. The more questions you ask sometimes the more answers you have to give.

Just the opposite in my opinion, if you don't give enough details the thread just grows, full of useless answers, because they aren't answering the required question.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top