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.

uart bit banging

Status
Not open for further replies.
I have been taking some time reading the asm on datasheet of the pic16f, the block diagram makes alot more sense now of what is going on under there! but also so many questions, for starts I understand that the w register is the one feeding the alu and k is when passing in a literal value,

but what are the f and b registers? i did not see them in the block diagram.

also I am aware of what the stack basically is and how to keep it from overflowing .... but how does it actually work, what values is it storing there when i go in to each layer?

also I am looking at the descriptions of the operands and even those are confusing even if they are in English, such as:
Inclusive OR W with f
Swap nibbles in f
Rotate Left f through Carry

and where do the answers go after the operation is done.....ie..what/where is the d register, or is that exactly what d is defining?
I know we have working tutorials of this stuff, but is there one kicking around that explains each of the operands in a little more detail?
 
More back to the topic though, I have slowed down the clock and 0 'd osctune, and then re-calibrated my timed operations,
I am able to receive and decode my remote pulse codes, however repeating them is still somewhat of a problem..

to debug i have traced the original pulse code on the scope that is going into the TSOP (TSOP IR RX is on INT0 pin, and echoed in TMR0 interrupt)
then i use a mirror to reflect the IR that my device is trying to echo, back in to its own TSOP and trace that on the scope
so far I am able to confirm that the pulse widths are in good .... fairly accurate timings...but the LG TV is still ignoring the instruction. Also it difficult to trace the full pulse code since it is so long

One problem in my code I can think of is that my read variables are 32-bit , while the actual pulse code is 27-28 bits, which would add a few unnecessary 0-pulses on the echo... I'm thinking maybe I need another 8bit variable that will define the terminated position... since i cant store a 2 as terminator in the 32-bit part ..... maybe there is a trick or other idea?

Again other things I fear here are timing, accuracy and wonder how much each of the pulses on/off times count ..... any chance someone has done this before /or has ideas? Or foresees other things im up against?
 
Last edited:
Again other things I fear here are timing, accuracy and wonder how much each of the pulses on/off times count ..... any chance someone has done this before /or has ideas? Or foresees other things im up against?

Transmitting IR is pretty trivial, and I've done numerous different types - but not LG (as far I know - I'm not sure what scheme LG use?)

The IR code in my tutorials is pretty easy to alter, and I've used that as the basis for my various transmitters.
 
Inclusive OR is just OR (as opposed to eXclusive OR - XOR).

Both apply the corresponding operation to every bit of the operands.

a OR b - produces 1 if either a or b is 1, 0 if both a and b are 0.
a XOR b - produces 1 if a and b are different, 0 if a and b are the same.

Nibble is half a byte.

Carry is a flag stored in the STATUS register. It's typically set in arithmetic operations. Say

Code:
movlw .200
addlw .100

200 + 100 = 300. This won't fit into W, so you get 300 - 256 = 44 in W. Carry flag gets set to indicate that the truncation took place, cleared otherwise.
 
The bread board computer was interesting , but would not trust all those BB connections, I could not see any reference to logic used ? My first processor was a CDP1802 , found it easy to machine code.(c 1979 cost $15 + post from RCA in US. ) .
 
I have been taking some time reading the asm on datasheet of the pic16f, the block diagram makes alot more sense now of what is going on under there! but also so many questions, for starts I understand that the w register is the one feeding the alu and k is when passing in a literal value,

but what are the f and b registers? i did not see them in the block diagram.

also I am aware of what the stack basically is and how to keep it from overflowing .... but how does it actually work, what values is it storing there when i go in to each layer?

also I am looking at the descriptions of the operands and even those are confusing even if they are in English, such as:
Inclusive OR W with f
Swap nibbles in f
Rotate Left f through Carry

and where do the answers go after the operation is done.....ie..what/where is the d register, or is that exactly what d is defining?
I know we have working tutorials of this stuff, but is there one kicking around that explains each of the operands in a little more detail?


Hi,

About stack overflow, what i always did was just make sure i dont call too many subroutines. I dont remember now how deep the stack was, but if i call a subroutine that calls a subroutine that calls a subroutine, that's usually enough.

About getting something to 'repeat', i am not sure what you are trying to repeat.
If you have to repeat the transmit code, just run it again but only when the next frame starts. You had to have measured the frame time or else guessed (#6 below).
Also, some codes do not repeat exactly they have a different code for the repeat frame.

After studying several remotes now i find that they can vary quite a lot although they do have similarities.
All that i have examined have the following properties:
1. A start burst.
2. A short length burst.
3. A long length burst (often twice the short length burst).
4. A short silence delay.
5. A long silence delay (often twice the short silence delay).
6. A certain frame repeat period (may have longer silence delay).
7. Either the same code or different code for the repeat signal.
8. The carrier frequency.
9. The code set.

If you can discover the above for a remote you can control the device it is meant for.
With #9 the code set can be small or very large. With a large code set it may be harder to generate codes without detecting them from the old remote first, but with a small code set it is relatively easy to generate codes even without having the old remote just by testing each code to see it's effect on the device.
Most of the codes that have a variable burst time do not have a variable delay time, and those that have a variable delay time do not have a variable burst time although the start pulse may be different. So codes look like this (H=burst 1 period, L=silence one period):
HHLHHLHLHLHHL

or like this:
HLLHLLHLHLHLLH

but not like this:

HHLHHLHLLHLLHH

but i suppose that could be possible with remotes i do not have presently.

Because some of the codes are so simple to read on the scope, sometimes i just count the short bursts and sometimes the short and long bursts and create the programmed code that way. For example, if i see the start pulse, then 5 short bursts with 5 short delays, then 2 long bursts with 2 short delays, i would code that as simply as:
1111122

although this can also be coded as:
511

but that is for transmit codes that always have the same length delay periods (except at the start and end).

But anyway, you dont have to stick with the hex coding scheme if you dont want to have to keep converting to and from hex. If you have a short pulse and code that as 1 and then a long pulse and code that as 2, you've just coded the pulse width itself for example. Of course with only two different lengths you can code these as 0 and 1, so your code would end up being in binary anyway: 01110111, etc., and because each remote has it's own start and frame period, you always apply that anyway. Sometimes the address part is the same too for each and every code, so you could send that separately.

What else i find is that very short delays inserted into the stream dont seem to matter even though they dont belong there. For example, if you call a subroutine to generate the start signal, then call a different routine to send the code, then another routine for the ending sequence, the time it takes for each call and return dont seem to matter to the device. I never investigated how much i could get away with though.
 
Last edited:
What else i find is that very short delays inserted into the stream dont seem to matter even though they dont belong there. For example, if you call a subroutine to generate the start signal, then call a different routine to send the code, then another routine for the ending sequence, the time it takes for each call and return dont seem to matter to the device. I never investigated how much i could get away with though.

The whole point of the coding systems used is that exact timing doesn't matter, as the IR link completely changes it anyway - by quite a high percentage sometimes.

Subroutine calls don't make any difference because they are only microseconds, far too small to have any effect.
 
I believe the stack fills up when you do things like this if{while{for{if{while{for{}}}}}} <-- so that would take up 6 stacks, I often eliminate consumption by doing things such as replacing while(1) with goto:begining; and/or creating global flags and calling if's .... more over it doesn't matter that much but I was just curious as to what value is actually stored in a stack that is so important, ie is it the return value place holder , or a place to store the if or while instruction that it is in?

No worry's, i won't be building a bread board computer any time soon, mine would never be as tidy as that either! but it was a great lesson in how all the registers tie in together. What i find most fascinating is how instructions are decoded to simply being which set and enable pins are active and how the data passes in the microsteps (it also solves the mystery of why all these IC's that i buy have set and enable pins!)

genius Nigel! I forgot that these would use a standard "protocol", so i searched it! LG uses the NEC protocol! Which adds another mystery of why i only received 28 bits!
I will do up a sub to follow the protocol better and see if transmitting is then more successful. I think my worry was mostly about pulse time accuracy. (things like the protocol says 540us, but actually I was delaying 600us .. its difficult for scope to get zoomed in that close and use the one-shot ... mostly cause of the long start bit)
https://www.sbprojects.com/knowledge/ir/nec.php
 
I believe the stack fills up when you do things like this if{while{for{if{while{for{}}}}}} <-- so that would take up 6 stacks, I often eliminate consumption by doing things such as replacing while(1) with goto:begining; and/or creating global flags and calling if's .... more over it doesn't matter that much but I was just curious as to what value is actually stored in a stack that is so important, ie is it the return value place holder , or a place to store the if or while instruction that it is in?

Assuming you're using C, then it uses it's own stack - so you're not limited by the processors small stack (although it's still limited).

If you're using assembler, then YOU are in charge, make sure you don't exceed the stack depth or you WILL be sorry :D

Bear in mind that interrupts use the stack as well - so if you're using interrupts this further restricts the stack space you have - and is one reason why it's a bad idea to have subroutine calls from within ISR's.

genius Nigel! I forgot that these would use a standard "protocol", so i searched it! LG uses the NEC protocol!

I did the NEC protocol for a local theme park, to add manual buttons to small media players that only have remote control operation.

I simply wired a PIC to the back of the IR receiver, and inserted the data directly - the IR remote still worked as well :D

Quick edit: - I used the PICKit2 to capture the signals from the remote, in order to identify what I needed, here's one of the keys, this is actually the power key:

Power.png


(things like the protocol says 540us, but actually I was delaying 600us .. its difficult for scope to get zoomed in that close and use the one-shot ... mostly cause of the long start bit)

Like I said before, it doesn't matter, the output from the receiver won't be anything like the timing from the specification, and will vary with distance from the transmitter as well.
 
I believe the stack fills up when you do things like this if{while{for{if{while{for{}}}}}} <-- so that would take up 6 stacks, I often eliminate consumption by doing things such as replacing while(1) with goto:begining; and/or creating global flags and calling if's .... more over it doesn't matter that much but I was just curious as to what value is actually stored in a stack that is so important, ie is it the return value place holder , or a place to store the if or while instruction that it is in?

No worry's, i won't be building a bread board computer any time soon, mine would never be as tidy as that either! but it was a great lesson in how all the registers tie in together. What i find most fascinating is how instructions are decoded to simply being which set and enable pins are active and how the data passes in the microsteps (it also solves the mystery of why all these IC's that i buy have set and enable pins!)

genius Nigel! I forgot that these would use a standard "protocol", so i searched it! LG uses the NEC protocol! Which adds another mystery of why i only received 28 bits!
I will do up a sub to follow the protocol better and see if transmitting is then more successful. I think my worry was mostly about pulse time accuracy. (things like the protocol says 540us, but actually I was delaying 600us .. its difficult for scope to get zoomed in that close and use the one-shot ... mostly cause of the long start bit)
https://www.sbprojects.com/knowledge/ir/nec.php


Hi,

If you are not using assembler than you have to look at the disassembled code to see how many levels of stack it uses i guess. I always used asm for this when i used the PIC chips.

NEC was probably one of my favorites. I have other protocols that dont seem to have any standard friendly names. I know them only by a representative code frame.
 
Normally the stack on medium pics is 255 bytes.... But!! you can make it bigger... There is a linker script with the size defined inside.. Normally you wont use anywhere near that... One of the perks of C is the pointer system.... As good as having all global variables...

When nesting functions, just tread carefully...
 
I kind of put this together

I made a simple code to send serial data out at 9600 baud rate it works fine for them time when you want to send
quick data to the serial port. It's good for a quick data link.
Code:
 ;**********************************************************************
;                                                                     *
;    Filename:    serial.asm                                        *
;    Date:                                                            *
;    File Version:                                                    *
;                                                                     *
;    Author:   Burt E Ratliff                                         *
;    Company:                                                         *
;                                                                     * 
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files Required: P12F508.INC                                      *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;                                                                     *
;**********************************************************************
list      p=12F508            ; list directive to define processor
#include <p12F508.inc>        ; processor specific variable definitions
__CONFIG   _MCLRE_OFF & _CP_OFF & _WDT_OFF & _IntRC_OSC
; pin assignments
   
#define  TX  GPIO,0  ; transmit pin on GP0
;***** VARIABLE DEFINITIONS
     UDATA
buffer     res    1            
counter    res    1 
Count      res    1 
;**********************************************************************
; Internal RC calibration value is placed at location 0x1FF by Microchip
; as a movlw k, where the k is a literal value.
RESET   CODE    0x000           ; effective reset vector
       movwf   OSCCAL          ; update OSCCAL with factory cal value 
   
   goto    init              ; jump to main program
init 
movlw b'00000000'   ; set I/O
   tris    GPIO
bsf  TX
movlw 'b'               ; sets text to loads buffer with 
call start
movlw 'e'
call start
movlw '8'
call start
movlw '0'
call start
movlw 'b'
   call start
movlw 'e'
   call start
movlw ' '
call start
movlw 'w'
call start
movlw 'a'
call start
movlw 's'
call start
movlw ' '
call start
movlw 'h'
call start
movlw 'e'
call start
movlw 'r'
call start
movlw 'e'
call start
movlw 0x0A
call start
movlw 0x0D
call start
   goto init   ;loop for ever
start
movwf buffer
movlw 0x08
movwf counter        ; counts the 8 bits 
   bcf   TX             ; set TX low
   call  BItdelay       ; delay to get a 9600 bit rate
TXLoop  
   rrf   buffer ,f      ;send one bit
   btfss STATUS ,C      ;  
   bcf   TX             ;
   btfsc STATUS ,C  ;
   bsf   TX  ;
   call  BItdelay  ;
   decfsz counter,f     ;test if all done
   goto  TXLoop  ;
   bsf   TX  ;
   call  BItdelay  ;
   return
BItdelay                 ; timing delay 
   movlw 0x17
   movwf  Count  
Wait    
   nop 
   decfsz Count ,f
   goto   Wait
   return 
END  ; directive 'end of program'
 
2 stacks!!??
well baby steps anyway!
my first asm!:
Code:
            PORTC |= 0b00100000; 
            __delay_us(5); 
            PORTC &= 0b11011111;
            __delay_us(2);
            asm("NOP");
            asm("NOP");
        counter--;
but when i try more advanced things i get repeat definition error:
Code:
void IRon(int delayTime)
{ 
while (counter > 0){
#asm
BItdelay                 ; timing delay<----repeat definition error here
   movlw 0x17
   movwf  Count
#endasm
}}
 
Last edited:
Can you post all your code?

It may be that you lack parentheses - try bltdelay ();

Mike
 
Well posting only part of the code (and not in code tags) makes it impossible to make suggestions, C is particularly bad in this respect as errors very often are no where near where the error is flagged.
 
quite rite, I have fixed post 54
but it does not like this code still:

Code:
int main(int argc, char** argv)
{ 
while (counter > 0){
#asm
   movlw 0x17
   movwf  Count
#endasm
}}

... even with semicolons
 
Last edited:
Are you compiling with C?? Or are you using an assembler

The code doesn't do anything.. The quick and easy way in C to do a delay routine is using the inbuilt __delay_us();
But you need to define the XTAL you are using.

C:
#include<xc.h>

#define _XTAL_FREQ 4000000 // or whatever!

void main(void)
   }
   __delay_us(20);
   {

This gives exact timings....
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top