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.

Output = Input - Problems

Status
Not open for further replies.

adamthole

New Member
I am having some trouble having an output pin mimic an input pin. I have a program where all I want to happen is an output pin do exactly the same thing as the input pin. To test this I wrote a short program and put a 4KHz clock signal on the input and tested the frequency of both. The input was 4KHz, but the output was only between 500 and 600 Hz. I am running at 8MHz, so it should have no problem with the 4KHZ, right? Here is my code. It is on a 16F88, internal 8MHz clock, clean power source w/caps, SourceBoost compiler. BTW, the final program will do much more than this, if you are curious why this is written in C and not assembly.

Code:
#pragma DATA 0x2007, 0b0001111100010000

#include <system.h>

bit iCLK @ PORTA.2;

bit pCLK;

bit oCLK @ PORTB.1;

void main()
{
	//*********************//
	// configure I/O ports //
	//*********************//
    portb   = 000000000b;
    trisb   = 000000000b; //0 = Output, 1 = Input
    porta   = 00000000b;     
    trisa   = 11111111b; //0 = Output, 1 = Input
    osccon  = 01110000b; //internal oscillator @ 8MHz
	cmcon   = 00000111b; //comparators off
	ansel   = 00000001b; //AN0 on (RA0)
	
	pCLK = iCLK;
	oCLK = iCLK;
	
	while(1)
	{
		if (iCLK != pCLK)
		{
			pCLK = iCLK;
			oCLK = pCLK;
		}
	}
}

I also tried a more straight forward approach where I would just set the output to the input time every time, without checking the current state. That one is even weirder. 4KHz in, 396 KHz out!?

Code:
#pragma DATA 0x2007, 0b0001111100010000

#include <system.h>

bit iCLK @ PORTA.2;

bit pCLK;

bit oCLK @ PORTB.1;

void main()
{
	//*********************//
	// configure I/O ports //
	//*********************//
    portb   = 000000000b;
    trisb   = 000000000b; //0 = Output, 1 = Input
    porta   = 00000000b;     
    trisa   = 11111111b; //0 = Output, 1 = Input
    osccon  = 01110000b; //internal oscillator @ 8MHz
	cmcon   = 00000111b; //comparators off
	ansel   = 00000001b; //AN0 on (RA0)
	
	pCLK = iCLK;
	oCLK = iCLK;
	
	while(1)
	{
		oCLK = iCLK;
	}
}

Any idea what is causing either problem? I am almost embarrassed to post this because it is such a silly program, but I cannot figure it out.
 
hi adam,
Whats the mark/space ratio of the 4KHz input clock, what are you using as a square wave pulse generator.
 
It is the clock signal of an I2C device, with the appropriate pull up resistor. I have tried it with and without the pull up resistor, giving the same results. I assume the duty cycle is 50%, but I don't know that for a fact. I will check...
 
A couple of "scratching at straw" suggestions, is the config valid - I've not come across a compiler that takes 0b to indicate binary and a WD timeout could explain things. Also, do you need to tell the compiler that iCLK is volatile, this is doubtful as if this was the case it wouldn't work at all.

Mike.
 
I checked the duty cycle, and it is 99.1%. So, I think the pulse is just too fast for my PIC to pick up at 8MHz. I'll try it with 20 MHz and go from there.

Thanks for the suggestions Pommie. The config should be valid, I haven't had any problems with it in the past. The WDT should be disabled, if I did it right.
 
A 16F88 at 8MHz should have no problems seeing a 4KHz clock, that equates to 500 instructions per pulse. Many people here have bit banged RS232 at 9600 Baud on a 8Mhz pic.

Can you post the asm that is produced by the compiler?

Mike.
 
It is a 4KHz clock, but the duty cycle is 99.1%, so the amount of time the clock is low is very short. I haven't done the calculation for how many instructions that would account for, but I assume it would be very few. Here is the ASM:

Code:
;/////////////////////////////////////////////////////////////////////////////////
;// Code Generator: BoostC Compiler - http://www.sourceboost.com
;// Version       : 6.60
;// License Type  : Pro License
;// Limitations   : PIC12,PIC16 max code size:Unlimited, max RAM banks:Unlimited
;/////////////////////////////////////////////////////////////////////////////////

	include "P16F88.inc"
; Heap block 0, size:112 (0x00000110 - 0x0000017F)
__HEAP_BLOCK0_BANK               EQU	0x00000002
__HEAP_BLOCK0_START_OFFSET       EQU	0x00000010
__HEAP_BLOCK0_END_OFFSET         EQU	0x0000007F
; Heap block 1, size:96 (0x00000190 - 0x000001EF)
__HEAP_BLOCK1_BANK               EQU	0x00000003
__HEAP_BLOCK1_START_OFFSET       EQU	0x00000010
__HEAP_BLOCK1_END_OFFSET         EQU	0x0000006F
; Heap block 2, size:80 (0x000000A0 - 0x000000EF)
__HEAP_BLOCK2_BANK               EQU	0x00000001
__HEAP_BLOCK2_START_OFFSET       EQU	0x00000020
__HEAP_BLOCK2_END_OFFSET         EQU	0x0000006F
; Heap block 3, size:79 (0x00000021 - 0x0000006F)
__HEAP_BLOCK3_BANK               EQU	0x00000000
__HEAP_BLOCK3_START_OFFSET       EQU	0x00000021
__HEAP_BLOCK3_END_OFFSET         EQU	0x0000006F
CompGblVar12                     EQU	0x00000020 ; bit:0
CompGblVar13                     EQU	0x00000020 ; bit:1
gbl_status                       EQU	0x00000003 ; bytes:1
gbl_indf                         EQU	0x00000000 ; bytes:1
gbl_tmr0                         EQU	0x00000001 ; bytes:1
gbl_pcl                          EQU	0x00000002 ; bytes:1
gbl_fsr                          EQU	0x00000004 ; bytes:1
gbl_porta                        EQU	0x00000005 ; bytes:1
gbl_portb                        EQU	0x00000006 ; bytes:1
gbl_pclath                       EQU	0x0000000A ; bytes:1
gbl_intcon                       EQU	0x0000000B ; bytes:1
gbl_pir1                         EQU	0x0000000C ; bytes:1
gbl_pir2                         EQU	0x0000000D ; bytes:1
gbl_tmr1l                        EQU	0x0000000E ; bytes:1
gbl_tmr1h                        EQU	0x0000000F ; bytes:1
gbl_t1con                        EQU	0x00000010 ; bytes:1
gbl_tmr2                         EQU	0x00000011 ; bytes:1
gbl_t2con                        EQU	0x00000012 ; bytes:1
gbl_sspbuf                       EQU	0x00000013 ; bytes:1
gbl_sspcon                       EQU	0x00000014 ; bytes:1
gbl_ccpr1l                       EQU	0x00000015 ; bytes:1
gbl_ccpr1h                       EQU	0x00000016 ; bytes:1
gbl_ccp1con                      EQU	0x00000017 ; bytes:1
gbl_rcsta                        EQU	0x00000018 ; bytes:1
gbl_txreg                        EQU	0x00000019 ; bytes:1
gbl_rcreg                        EQU	0x0000001A ; bytes:1
gbl_adresh                       EQU	0x0000001E ; bytes:1
gbl_adcon0                       EQU	0x0000001F ; bytes:1
gbl_option_reg                   EQU	0x00000081 ; bytes:1
gbl_trisa                        EQU	0x00000085 ; bytes:1
gbl_trisb                        EQU	0x00000086 ; bytes:1
gbl_pie1                         EQU	0x0000008C ; bytes:1
gbl_pie2                         EQU	0x0000008D ; bytes:1
gbl_pcon                         EQU	0x0000008E ; bytes:1
gbl_osccon                       EQU	0x0000008F ; bytes:1
gbl_osctune                      EQU	0x00000090 ; bytes:1
gbl_pr2                          EQU	0x00000092 ; bytes:1
gbl_sspadd                       EQU	0x00000093 ; bytes:1
gbl_sspstat                      EQU	0x00000094 ; bytes:1
gbl_txsta                        EQU	0x00000098 ; bytes:1
gbl_spbrg                        EQU	0x00000099 ; bytes:1
gbl_ansel                        EQU	0x0000009B ; bytes:1
gbl_cmcon                        EQU	0x0000009C ; bytes:1
gbl_cvrcon                       EQU	0x0000009D ; bytes:1
gbl_adresl                       EQU	0x0000009E ; bytes:1
gbl_adcon1                       EQU	0x0000009F ; bytes:1
gbl_wdtcon                       EQU	0x00000105 ; bytes:1
gbl_eedata                       EQU	0x0000010C ; bytes:1
gbl_eeadr                        EQU	0x0000010D ; bytes:1
gbl_eedath                       EQU	0x0000010E ; bytes:1
gbl_eeadrh                       EQU	0x0000010F ; bytes:1
gbl_eecon1                       EQU	0x0000018C ; bytes:1
gbl_eecon2                       EQU	0x0000018D ; bytes:1
gbl_iCLK                         EQU	0x00000005 ; bit:2
gbl_pCLK                         EQU	0x00000020 ; bit:2
gbl_oCLK                         EQU	0x00000006 ; bit:1
	ORG 0x00000000
	GOTO	_startup
	ORG 0x00000003
main
; { main ; function begin
	BCF STATUS, RP0
	BCF STATUS, RP1
	CLRF gbl_portb
	BSF STATUS, RP0
	CLRF gbl_trisb
	BCF STATUS, RP0
	CLRF gbl_porta
	MOVLW 0xFF
	BSF STATUS, RP0
	MOVWF gbl_trisa
	MOVLW 0x70
	MOVWF gbl_osccon
	MOVLW 0x07
	MOVWF gbl_cmcon
	MOVLW 0x01
	MOVWF gbl_ansel
	BCF STATUS, RP0
	BCF gbl_pCLK,2
	BTFSC gbl_iCLK,2
	BSF gbl_pCLK,2
	BCF gbl_oCLK,1
	BTFSC gbl_iCLK,2
	BSF gbl_oCLK,1
label4026532599
	MOVLW 0x00
	BTFSC gbl_pCLK,2
	XORLW 0x01
	BTFSC gbl_iCLK,2
	XORLW 0x01
	ANDLW 0xFF
	BTFSC STATUS,Z
	GOTO	label4026532599
	BCF gbl_pCLK,2
	BTFSC gbl_iCLK,2
	BSF gbl_pCLK,2
	BCF gbl_oCLK,1
	BTFSC gbl_pCLK,2
	BSF gbl_oCLK,1
	GOTO	label4026532599
; } main function end

	ORG 0x00000029
_startup
	BCF STATUS, RP0
	BCF STATUS, RP1
	BCF CompGblVar12,0
	BCF CompGblVar13,1
	BCF PCLATH,3
	BCF PCLATH,4
	GOTO	main
	ORG 0x00002007
	DW 0x1F10
	END
 
I'm also having some trouble getting it to run with a 20MHz clock. I only need to change the oscon register and the configuration word located at 2007h, right?

Here is what I am putting for both:

#pragma DATA 0x2007, 0b0001111100010000
osccon = 00000101b;

I'm not sure if they are right. Probably not, because I haven't gotten it to work yet. I will keep trying.
 
Could I suggest using the B0 interrupt flag - not the interrupt, just the flag.

If your input is on RB0 then INTF becomes set on a rising edge.

Something like,
Code:
	while(1){
		while(!intcon,intf);
		set_bit(oCLK);
		clear_bit(oCLK);
		clear_bit(intcon,intf);
	}

BTW, the code produced by the compiler is rather scary and could cause some nasty bugs. For the oCLK = iCLK it does the equivalent of iCLK = 0:if oCLK=1 then iCLK=1. This will always give a pulse out.:eek: :eek:

This is one reason I don't like compilers for microcontrollers.

Mike.
 
With a duty cycle of 99%, the pulse is only 5 cycles long. That is why I suggested using an edge triggered input.

The compiler really doesn't help.

Gramo,
What code does your compiler produce when assigning bits such as,
iCLK = oCLK;
The boostC compiler produces
Code:
	BCF gbl_iCLK,1
	BTFSC gbl_oCLK,2
	BSF gbl_iCLK,1
This is why he got an output of 396KHz:eek:

Mike.
 
Program;
Code:
Device = 16F628A
XTAL = 8

Symbol Input_Pin = PORTA.0
Symbol Output_Pin = PORTB.0

Input Input_Pin
Low Output_Pin

While 1 = 1
        If Input_Pin <> Output_Pin Then
           Output_Pin = Input_Pin
        EndIf
Wend

Assembler;
Code:
;----------------------------------------------------------
; Code Produced by the PROTON+ LITE Compiler. Version 3.1.1
; Copyright Rosetta Technologies/Crownhill Associates
; Written by Les Johnson. July 14 2005
;----------------------------------------------------------
 NOLIST
 #include "E:\PROGRAM FILES\PROTONIDELITE\EXAMPLE.PBP"
 LIST

	#DEFINE INPUT_PIN PORTA,0
	#DEFINE OUTPUT_PIN PORTB,0
F2_SOF equ $ ; EXAMPLE.PRP
F2_EOF equ $ ; EXAMPLE.PRP
F1_SOF equ $ ; EXAMPLE.BAS
F1_000007 equ $ ; in [EXAMPLE.BAS] Input Input_Pin
	bsf STATUS,5
RAM_BANK = 1
	bsf TRISA,0
F1_000008 equ $ ; in [EXAMPLE.BAS] Low Output_Pin
	bcf STATUS,5
RAM_BANK = 0
	bcf PORTB,0
	bsf STATUS,5
RAM_BANK = 1
	bcf TRISB,0
F1_000010 equ $ ; in [EXAMPLE.BAS] While 1 = 1
bc@LL1
	bcf STATUS,5
RAM_BANK = 0
F1_000011 equ $ ; in [EXAMPLE.BAS] If Input_Pin <> Output_Pin Then
	movf PORTA,W
	xorwf PORTB,W
	andlw 1
	btfsc STATUS,2
	GoTo bc@LL4
F1_000012 equ $ ; in [EXAMPLE.BAS] Output_Pin = Input_Pin
	btfsc PORTA,0
	bsf PORTB,0
	btfss PORTA,0
	bcf PORTB,0
F1_000013 equ $ ; in [EXAMPLE.BAS] EndIf
bc@LL4
F1_000014 equ $ ; in [EXAMPLE.BAS] Wend
	GoTo bc@LL1
bc@LL2
F1_EOF equ $ ; EXAMPLE.BAS
 LIST
Asm@End@
	End
 
That's what I would expect a [good] compiler to do,
Code:
F1_000012 equ $ ; in [EXAMPLE.BAS] Output_Pin = Input_Pin
	btfsc PORTA,0
	bsf PORTB,0
	btfss PORTA,0
	bcf PORTB,0
Perhaps someone should point this out to the BoostC guys.

Mike.
 
Thanks for the help guys, you have been great. I have contacted the BoostC guys about the compiler issue. I hear they are pretty good about fixing issues when they are notified.

In the meantime I will switch over to using the interrupt and see what I can do from there.

Thanks!
 
adamthole said:
Thanks for the help guys, you have been great. I have contacted the BoostC guys about the compiler issue. I hear they are pretty good about fixing issues when they are notified.

It's a good idea to use volatile specifier for variables mapped to port pins like in the original post. Instead of:

bit iCLK @ PORTA.2;

do:

volatile bit iCLK @ PORTA.2;

This will tell the BoostC compiler to apply different code generation so that value of such variable is not changed in the middle of an expression.

For example for an expression (from post above):

iCLK = oCLK;

a non volatile variable will produce:

BCF gbl_iCLK,1
BTFSC gbl_oCLK,2
BSF gbl_iCLK,1


while if iCLK is declared volatile code will be (node that now value of iCLK does not change to intermediate):

BTFSC gbl_oCLK,2
BSF gbl_iCLK,1
BTFSS gbl_oCLK,2
BCF gbl_iCLK,1


and some very cautious code that uses both iCLK and oCLK volatile will have:

CLRF CompTempVar476
BTFSC gbl_oCLK,2
INCF CompTempVar476, F
BTFSC CompTempVar476,0
BSF gbl_iCLK,1
BTFSS CompTempVar476,0
BCF gbl_iCLK,1


Pavel
 
That's good to know, thanks for clearing that up. Ironically, declaring volatility was one of my first suggestions.

I will certainly be having another look at BoostC. It seems a lot more usable than when I last looked.

Mike.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top