|
|
View previous topic :: View next topic |
Author |
Message |
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Thu Mar 11, 2021 12:50 pm |
|
|
On a modern compiler, the pwm_off syntax would work, provided the output
'floats off'. |
|
|
Denny9167
Joined: 15 Feb 2021 Posts: 49
|
|
Posted: Sun May 23, 2021 5:03 pm |
|
|
I finally found some code that I could use for the 12F1822, using the NEC protocol, Ive been studying alot of assembly code, and seem to have a better grasp on it, I would like to learn more C, but at least I think Im getting a head start. I'll post the asm file. It would be nice to have a C version of this.
an include file contains all the setup info.
Code: |
;**********************************************************************
; BROWN AUDIO LABS *
; PROJECT: Volume and Relay Control *
; INTERNAL CLOCK: 4Mhz *
; NEC FORMAT @38KHz *
; ADDRESS ID = 0xBA *
; CMD = 0x10 *
; CMD = 0x20 *
; CMD = 0x30 *
; CMD = 0x40 *
; CMD = 0x50 *
;**********************************************************************
include "devices_setup(NEC).inc"
CLOCK_RATIO equ CLOCK_FREQUENCY/4000000 ; 8MHz = 1/2usec per ins, 4MHz = 1usec per ins
; 8-pin DIP
; VDD -|1 8|- VSS
; GP5 -|2 7|- GP0
; GP4 -|3 6|- GP1
; GP3 -|4 5|- GP2
;
#define PIN_IR 3 ; MCLR can only be an input
#define PIN_MTR1 0
#define PIN_MTR2 1
#define PIN_RLY1 2
#define PIN_RLY2 4
#define PIN_RLY3 5
#define RLY_MASK (1<<PIN_RLY1)|(1<<PIN_RLY2)|(1<<PIN_RLY3)
#define PINPORT_IR PORTIO,PIN_IR
#define PINPORT_MTR1 PORTIO,PIN_MTR1
#define PINPORT_MTR2 PORTIO,PIN_MTR2
#define PINPORT_RLY1 PORTIO,PIN_RLY1
#define PINPORT_RLY2 PORTIO,PIN_RLY2
#define PINPORT_RLY3 PORTIO,PIN_RLY3
#define TRIS_BITS (1<<PIN_IR)
ADDRS_ID equ 0xBA
MTR1_CMD equ 0x10
MTR2_CMD equ 0x20
RLY1_CMD equ 0x30
RLY2_CMD equ 0x40
RLY3_CMD equ 0x50
cblock
ADDRS
INV_ADDRS
CMD
INV_CMD
endc
; We sample the input line in chunks, and make decisions based on the 8-bit counts of the high/low durations.
; A chunk is a number of samples, within each chunk we check for at least 75% of the samples being high or low.
; Longer chunks handle noise better, but give less resolution for the overall duration timing.
CHUNK_USEC equ 55
CHUNK_INS equ CHUNK_USEC*INS_PER_USEC
; Sanity check the chunk size
#if (CHUNK_INS%5)!=0
error Chunk length must be a multiple of 5 instructions
#else
#if (CHUNK_INS<40)
error Chunk length less than 8 samples
#else
#if (((92632/(10*CHUNK_USEC))*150/100)>=256)
error Chunk length too short, 150% of 9.2ms is more than 256 chunks
#else
#if ((5789/(10*CHUNK_USEC))<3)
error Chunk length too long, need at least 3 samples in the 0.5789ms pulses
#endif
#endif
#endif
#endif
; With 55usec chunks (4MHz=11 loops, 8MHz=22 loops) the timings we are interested in are:
; Duration Chunks Desc
; 9.2632ms ~168 (hi) start pulse
; 0.5789ms 10.5 (hi) data / stop high bit
; 4.6316ms ~84 (lo) gap after start bit
; 0.5789ms 10.5 (lo) data bit '0' gap
; 1.7368ms 31.5 (lo) data bit '1' gap
; Return the number of high chunks in FUNC_TMP0, and return STATUS,C set if we get an error (more than 256 high chunks)
time_hi:
clrf FUNC_TMP0
time_h1:
movlw CHUNK_INS/5
movwf FUNC_TMP1
movlw CHUNK_INS*2/(3*5)
movwf FUNC_TMP2 ; Target count is 2/3 high
time_h2:
btfss PINPORT_IR ; IR receiver outputs a low when we have a signal, so skip if high (so no signal)
decf FUNC_TMP2,F
decfsz FUNC_TMP1,F
BRA time_h2
bcf STATUS,C ; Assume no error
btfss FUNC_TMP2,7 ; Top bit should have gone negative, if was high for 2/3 or more of the samples
retlw 0x22 ; Now low, so return FUNC_TMP0 count
incfsz FUNC_TMP0,F
BRA time_h1
bsf STATUS,C ; Is too long (55usec*256=14.1msec)
retlw 0x33
; Return the number of low chunks in FUNC_TMP0, and return STATUS,C set if we get an error (more than 256 low chunks)
time_lo:
clrf FUNC_TMP0
time_l1:
movlw CHUNK_INS/5
movwf FUNC_TMP1
movlw CHUNK_INS*2/(3*5)
movwf FUNC_TMP2 ; Target count is 2/3 low
time_l2:
btfsc PINPORT_IR ; IR receiver outputs a low when we have a signal, so skip if low (so have signal)
decf FUNC_TMP2,F
decfsz FUNC_TMP1,F
BRA time_l2
bcf STATUS,C ; Assume no error
btfss FUNC_TMP2,7 ; Top bit should have gone negative, if was low for 2/3 or more of the samples
retlw 0x22 ; Now high, so return FUNC_TMP0 count
incfsz FUNC_TMP0,F
BRA time_l1
bsf STATUS,C ; Is too long (55usec*256=14.1msec)
retlw 0x33
; -----------------------------------------------------------------
STARTUP_CODE
clrf PORTIO
reset: ; Power on, or no codes for 100ms+
movlw ~((1<<PIN_MTR1)|(1<<PIN_MTR2))
andwf PORTIO,F ; Clear the up/down motor outputs
wait_reset:
movlw 1+(100000/(256*CHUNK_USEC)) ; Wait for 100ms+ worth of chunks
movwf FUNC_TMP3 ; time_lo/hi uses TMP0/1/2
wait_count:
decf FUNC_TMP3,F
btfsc FUNC_TMP3,7
BRA reset
clrf ADDRS
clrf INV_ADDRS
clrf CMD
clrf INV_CMD
bsf INV_CMD,0 ; When this bit pops out the top, we're done
call time_lo
btfsc STATUS,C
BRA wait_count ; timeout, so is still low!
; This is either a start bit (so upto 9ms on+4.5ms off) or a data bit (0.5789ms high)
call time_hi
btfsc STATUS,C
BRA reset ; timeout, so is still high!
movlw 5789*150/(CHUNK_USEC*1000) ; 578.9 usec*150%
subwf FUNC_TMP0,W ; W=Count-Target
btfss STATUS,C
BRA got_first ; Got borrow, so <15, so was the first bit, so skip wait
call time_lo
btfsc STATUS,C
BRA wait_count ; timeout, so is still low!
movlw 46316*50/(CHUNK_USEC*1000) ; Look for 50% of 4.6ms
subwf FUNC_TMP0,W ; W=Count-Target
btfss STATUS,C
BRA wait_count ; Got borrow, so <Target, so bad !
main_bit:
call time_hi
btfsc STATUS,C
BRA reset ; timeout, so is still high!
movlw (5789*150/(CHUNK_USEC*1000))-1 ; 578.9 usec*150%
subwf FUNC_TMP0,W ; W=Count-(Target-1)
btfsc STATUS,C
BRA reset ; No borrow, so >=(Target-1), so too long
got_first:
call time_lo
btfsc STATUS,C
BRA reset ; timeout, so is still lo!
movlw ((17368*150)/(CHUNK_USEC*1000))-1 ; Look for longer than 150% of 1736.8
subwf FUNC_TMP0,W ; W=Count-(Target-1)
btfsc STATUS,C
BRA check_rpt ; No borrow, so Count is really big, check if it's the repeat
movlw ((5789+17368)/(CHUNK_USEC*20))-1 ; Look for midpoint of 578.9usec and 1736.8usec
subwf FUNC_TMP0,W ; W=Count-(Target-1)
rlf INV_CMD,F ; the sub leaves the borrow/carry in C, shift into LSB
rlf CMD,F
rlf INV_ADDRS,F
rlf ADDRS,F
btfss STATUS,C
BRA main_bit ; Marker bit didn't ripple out, so go again
call time_hi ; Clear stop bit
comf INV_ADDRS,W
xorwf ADDRS,W
btfss STATUS,Z
BRA reset ; Device ID bits weren't compliments
comf INV_CMD,W
xorwf CMD,W
btfss STATUS,Z
BRA reset ; Code bits weren't compliments
movlw ADDRS_ID
xorwf ADDRS,W
btfss STATUS,Z
BRA reset ; Device ID isn't the one we're looking for
;
movlw MTR1_CMD
xorwf CMD,W
btfss STATUS,Z
BRA not_mtr1
is_mtr1:
bcf PINPORT_MTR2
bsf PINPORT_MTR1
BRA wait_reset ; All done
not_mtr1:
movlw MTR2_CMD
xorwf CMD,W
btfss STATUS,Z
BRA not_mtr2 ; Not motor2 code
is_mtr2:
bcf PINPORT_MTR1
bsf PINPORT_MTR2
BRA wait_reset ; All done
not_mtr2:
movfw CMD
xorlw RLY1_CMD
skpz
BRA not_rly1
is_rly1:
movlw ~(RLY_MASK)
andwf PORTIO,F
movlw 1<<PIN_RLY1
xorwf PORTIO,F ; Toggle pin
BRA wait_reset ; All done
not_rly1:
movfw CMD
xorlw RLY2_CMD
skpz
BRA not_rly2
is_rly2:
movlw ~(RLY_MASK)
andwf PORTIO,F
movlw 1<<PIN_RLY2
xorwf PORTIO,F ; Toggle pin
BRA wait_reset ; All done
not_rly2:
movfw CMD
xorlw RLY3_CMD
skpz
BRA not_rly3
is_rly3:
movlw ~(RLY_MASK)
andwf PORTIO,F
movlw 1<<PIN_RLY3
xorwf PORTIO,F ; Toggle pin
BRA wait_reset ; All done
not_rly3:
goto reset
; We got a reasonable length bit, followed by a really long gap, if it's the first bit, then it's a repeat
check_rpt:
movfw ADDRS
iorwf INV_ADDRS,W
iorwf CMD,W
btfss STATUS,Z
BRA wait_count ; Not first bit, we have some others, so reset
movlw 0x01
xorwf CMD,W
btfss STATUS,Z
BRA wait_count ; Not first bit
BRA wait_reset ; Was the first bit, so this was a repeat, leave the outputs as they are
end
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Mon May 24, 2021 2:13 am |
|
|
You do realise that this is code to _receive_ the NEC protocol, not to generate
it. |
|
|
Denny9167
Joined: 15 Feb 2021 Posts: 49
|
|
Posted: Mon May 24, 2021 4:31 am |
|
|
Ttelmah wrote: | You do realise that this is code to _receive_ the NEC protocol, not to generate
it. |
My apologies, I should have posted under a new thread. |
|
|
Denny9167
Joined: 15 Feb 2021 Posts: 49
|
|
Posted: Mon May 24, 2021 4:34 am |
|
|
The transmitter code
Code: |
;**********************************************************************
; BROWN AUDIO LABS *
; PROJECT: 5 button remote control *
; INTERNAL CLOCK: 4Mhz *
; NEC FORMAT @38KHz *
; DEVICE ID = 0xBA *
; CODE = 0x12 *
; CODE = 0x34 *
; CODE = 0x56 *
; CODE = 0x65 *
; CODE = 0x77 *
;**********************************************************************
include "devices_setup(NEC).inc"
; 8-pin DIP 12FXXX/16FXXXXX
; VDD 1 8 VSS
; GP5 2 7 GP0/ICSPDAT
; GP4 3 6 GP1/ICSPCLK
; Vpp/MCLR/GP3 4 5 GP2
;
#define PIN_LED 2 ; pin 2
#define PIN_BUT1 0 ; pin 7
#define PIN_BUT2 1 ; pin 6
#define PIN_BUT3 3 ; pin 4
#define PIN_BUT4 4 ; pin 3
#define PIN_BUT5 5 ; pin 2
#define PINPORT_LED PORTIO,PIN_LED
#define PINPORT_BUT1 PORTIO,PIN_BUT1
#define PINPORT_BUT2 PORTIO,PIN_BUT2
#define PINPORT_BUT3 PORTIO,PIN_BUT3
#define PINPORT_BUT4 PORTIO,PIN_BUT4
#define PINPORT_BUT5 PORTIO,PIN_BUT5
#define TRIS_BITS ((1<<PIN_BUT1)|(1<<PIN_BUT2)|(1<<PIN_BUT3)|(1<<PIN_BUT4)|(1<<PIN_BUT5))
DEVICE_ID equ 0xBA
PIN1_CODE equ 0x10
PIN2_CODE equ 0x20
PIN3_CODE equ 0x30
PIN4_CODE equ 0x40
PIN5_CODE equ 0x50
; ----------------------------------------------------------------------
cblock
TX_BUF:4
DBBUT
endc
; Do single 38KHz cycle, should be 26.3 usec, so 26us is 1.2% low, which is OK, but we tweak via the OSCCAL to run a bit slower
IR_ONOFF macro skip
bcf PINPORT_LED
WAIT_INS (13*INS_PER_USEC)-1 ; 13us high, inc set instruction
bsf PINPORT_LED
WAIT_INS ((13*INS_PER_USEC)-(1+(skip))) ; 13us low, inc clr instruction, and any extras
endm
; Send DEVICE_ID/!DEVICE_ID/W/!W as 32-bit NEC code
send_code
movwf FUNC_TMP1
movlw 352/2 ; 352 cycles of 38KHz = 9ms
movwf FUNC_TMP0
ir_start
IR_ONOFF 0
IR_ONOFF 3
decfsz FUNC_TMP0,F
BRA ir_start
movlw 4632/24 ; 4.5ms gap (=192*24us)
movwf FUNC_TMP0
ir_space
WAIT_INS (24*INS_PER_USEC)-3 ; 24 us per loop
decfsz FUNC_TMP0,F
BRA ir_space
movlw DEVICE_ID
movwf TX_BUF
movlw ~DEVICE_ID
movwf TX_BUF+1
movfw FUNC_TMP1
movwf TX_BUF+2
comf FUNC_TMP1,W
movwf TX_BUF+3
nec_ir_byte
movlw 32
movwf FUNC_TMP2
nec_ir_bit
IR_ONOFF 2
movlw 21
movwf FUNC_TMP0
nec_ir_bit_on
IR_ONOFF 3
decfsz FUNC_TMP0,F
BRA nec_ir_bit_on
rlf TX_BUF+3,F
rlf TX_BUF+2,F
rlf TX_BUF+1,F
rlf TX_BUF+0,F
movlw 3*44-1
btfss STATUS,C
movlw 44-1
movwf FUNC_TMP0
WAIT_INS (13*INS_PER_USEC)-8
nec_ir_bit_off
WAIT_INS (13*INS_PER_USEC)-3 ; 13us per loop
decfsz FUNC_TMP0,F
BRA nec_ir_bit_off
decfsz FUNC_TMP2,F
BRA nec_ir_bit
nec_ir_stop
IR_ONOFF 2
movlw 20
movwf FUNC_TMP0
nec_ir_stop_lp
IR_ONOFF 3
decfsz FUNC_TMP0,F
BRA nec_ir_stop_lp
ir_wait
movlw 80000/2560
movwf FUNC_TMP1
clrf FUNC_TMP0 ; 256*10us=2.56ms
ir_gap
WAIT_INS (10*INS_PER_USEC)-3
decfsz FUNC_TMP0,F
BRA ir_gap
decfsz FUNC_TMP1,F
BRA ir_gap
retlw 0x33
#if 1 ; DEBUG
morse_c
bsf PINPORT_LED
call wait_7_ins ; If off, then does 7+2=9
btfsc STATUS,C ; If on does 7+12=19
call wait_12_ins
bcf PINPORT_LED
retlw 1
#endif
; -----------------------------------------------------------------
#ifdef FEATURE_12BIT
;#define WAKEUP_LABEL main_loop ; 10F2xx don't return after sleep, they reset with special flags in STATUS. Branch here if detected
#endif
STARTUP_CODE
movlw 1<<PIN_LED
movwf PORTIO
main_loop:
btfsc PINPORT_BUT1
BRA not_but1
movlw PIN1_CODE
call send_code
BRA main_loop
not_but1:
btfsc PINPORT_BUT2
BRA not_but2
movlw PIN2_CODE
call send_code
BRA main_loop
not_but2:
btfsc PINPORT_BUT3
BRA not_but3
movlw PIN3_CODE
call send_code
BRA main_loop
not_but3:
btfsc PINPORT_BUT4
BRA not_but4
movlw PIN4_CODE
call send_code
BRA main_loop
not_but4:
btfsc PINPORT_BUT5
BRA no_but5
movlw PIN5_CODE
call send_code
BRA main_loop
no_but5: ; If any buttons down, skip the sleep
movlw TRIS_BITS
andwf PORTIO,W
xorlw TRIS_BITS
btfss STATUS,Z
BRA main_loop
bcf PINPORT_LED ; Should be off, but make sure, otherwise it will kill the battery
sleep ; See Microchip document TB082, Understanding Reset Events On The PIC10F20X (10F2xx will reset, not continue)
nop ; Some other devices will skip the instruction after a sleep, so put a NOP here
BRA main_loop
end
|
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|