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.

First PIC program - fresh eyes please!

Status
Not open for further replies.

throbscottle

Well-Known Member
I've just spent 2 days writing my first ever pic (or any sort of μC for that matter) program, which is also my first ever assembler program. It is to read and decode the output from a LTC24151 adc, (for a 6 digit voltmeter) auto-range up if there's an overflow, auto-range down if the reading is low enough, and output serial bcd with dp and blanking. It's intended to eventually handle function switching, though I haven't done that yet. No registers are used to hold the adc conversion result, it's just decoded directly. Output is lsb first. It's slightly incomplete - needs interrupts and a leading digit check.

It's initially written for 16F57 to get 3 ports, but that will probably change.

I haven't yet got a pic to try this on since I've not finally settled on everything it has to do.

So now my eyes have gone all funny, I'd really appreciate if anyone experienced with pic microcontrollers could look over it and see if I've done anything stupid, or in an overly long way.

Very many thanks in advance :D
 
I can't see anything syntactically wrong, I don't know how your ADC works.

It looks quite good for a first attempt, I don't program in ASM if I can help it now, C seems to do a good enough job for me! What I used to do, might sound a bit backwards, but I used to convert the ASM into C, just to see if it made logical sense, any high level language will do though. As long as all of your register bits are correct then it should be OK, I used a oscilloscope heavily in my ASM days, I do now also, but checking every edge etc was working as it should!

Wilksey
 
Thanks for that - it's so easy to do things in your own little world when the rest of the world knows so much better...

I realised I should make the display loop be on the outside after I posted my message, though, else no adc conversion = no display

The adc gives a 32 bit output, highest bit signals end of conversion, next 3 are dummy, sign and msb. If sign and msb are the same then it's over-range. The next 24 bits are the conversion result, the last 5 bits can be ignored or used in averaging. Chip select can be used to start a new conversion.

The only programs I've previously written have been some perl cgi scripts (just for my own interest), and with no formal training or peer review I've gone round the houses a few times with those! I like assembler though, really surprised how easy it was once I got my head round it.

Finding choosing a more suitable pic to be rather bewildering.

Thanks again.
 
Just a couple things...

Replace your #define pic16f57.inc statement with #include <P16F57.INC>. After including this file you don't have to define or equate SFR (special function register) names in your source file, though you'll find SFR names are defined in upper case.

RAM starts at address 0x10 in Bank 0 on the 16F57. You can use equate statements or cblock/endc to setup your variables if you're using absolute addressing mode.

Use proper bit names from the include file, like W and F instead of 0 and 1 for an instruction destination parameter, or like C and Z for status register bits.

I'm curious what the following instruction does or what you think it does?
Code:
     movf    low highbyte,W  ; check next digit

Please take time to learn how to use the MPLAB Simulator with Watch window to single step or run-to-breakpoint while viewing your variables, program counter, and status bits.

I've attached a couple small assembly language program examples.

Good luck. Have fun.

Cheerful regards, Mike
 
Last edited:
Just a couple things...

Replace your #define pic16f57.inc statement with #include <PIC16F57.INC>. After including this file you don't have to define or equate SFR (special function register) names in your source file, though you'll find SFR names are defined in upper case.

Okay, that explains that. I wondered why in all the tutorials I've looked at it uses friendly names for them and it didn't work for me! Ktechlab uses define, but doesn't recognise include.

I'm curious what the following instruction does or what you think it does?
Code:
     movf    low highbyte,W  ; check next digit

It's for range switching. The adc gives an over-range flag, but nothing to help the other way.
This is one of the reasons I wanted to get other people to have a look at my code, because I might be doing something stupid. highbyte, midbyte and lowbyte should contain 6 digits of bcd. The line in question should get the next most significant digit into w for testing.

What's supposed to happen is, if the first digit is zero, blank it, but the next 2 digits also need to be checked to see if the value being displayed begins >=25. (2.5v being full scale for the current version - I really should make life easier for myself and use 2v or 3v). So, if the next most significant digit is <2, switch range, if it's >2, don't switch, but if it's =2, test the next digit to see if it's <5, if it is, switch to a lower range, otherwise don't switch. There's probably a much simpler way to do it, but it's early days for me and I'm going with what I can understand.

Please take time to learn how to use the MPLAB Simulator with Watch window to single step or run-to-breakpoint while viewing your variables, program counter, and status bits.

Okay! I have mplabx but finding it rather daunting - maybe with your first piece of advice things will go better. I've been using ktechlab but it will only simulate 3 pics (and not the 57)

Thanks for the examples - I clearly have a lot to learn...
 
Please note the include file name is P16F57.inc and not PIC16F57.inc as I originally posted, and RAM memory in bank 0 is from 0x10 to 0x1F. My apologies...

May I ask about your ADC chip, please? I haven't found a datasheet for it yet. If the ADC output is 24 bits, wouldn't you need eight digits for the decimal value of the output?

Your use of "low" and "high" operators is incorrect and will not produce the upper and lower 4-bit nibbles you're looking for. Instead, use swapf highbyte,W and andlw 0x0F to get the upper nibble value 0x00..0x09 into WREG and use movf highbyte,W and andlw 0x0F to get the lower nibble value 0x00..0x09 into WREG.

I would recommend you include a line to set the configuration bits in your source file. Something like this;
Code:
        #include <P16F57.inc>

        errorlevel -302

  __config _HS_OSC & _WDT_OFF
;
;  variables
;
        cblock  0x10
highbyte                        ; bcd digits 5 and 6 (4 and 5)
midbyte                         ; bcd digits 3 and 4 (2 and 3)
lowbyte                         ; bcd digits 1 and 2 (0 and 1)
sign                            ; polarity of the input
range
temp
countin
digits                          ; represents low 7 bits (6 digits plus sign)
dp
digitcount
        endc
Looks like your bin-to-bcd routine is missing a label and a branch instruction. It simulates fine after I made the changes shown here;

Code:
convert
        movlw   d'23'           ; msb is already in lowbyte
        movwf   countin
nextbit                         ; <-- added missing label
        rlf     lowbyte,F
        rlf     midbyte,F
        rlf     highbyte,F
        bsf     PORTB,4         ; don't bother with a results register, just convert the value directly
        bcf     PORTB,4         ; trailing edge gets the bit
        bcf     lowbyte,0
        btfsc   PORTB,5         ; if it's a 1
        bsf     lowbyte,0       ; set a 1, otherwise it stays 0
        decf    countin,F
        skpnz                   ; (btfsc STATUS,2)
        retlw   0x00            ; get on with displaying

        movlw   highbyte
        movwf   FSR             ; fsr now holds address of highbyte
        call    onebyte
        movlw   midbyte
        movwf   FSR
        call    onebyte
        movlw   lowbyte
        movwf   FSR
        call    onebyte
        goto    nextbit         ; <-- added missing instruction

onebyte movlw   0x03
        addwf   INDF,W
        movwf   temp
        btfsc   temp,3          ; if <=7 skip next instruction
        movwf   INDF
        movlw   0x30
        addwf   INDF,W
        movwf   temp
        btfsc   temp,7          ; if <=7 skip next instruction
        movwf   INDF
        retlw   0x00

It seems a bit awkward using bin2bcd code as a pair of subroutines on a 12-bit core device with only two stack levels. The routine could be modified to use only one stack level and it would be both smaller and faster than your current code, but if you only need the routine in one place in your program there are a couple ways you could modify it to run in-line instead of as a subroutine. Here's an example (below) that uses 33 words of memory, no stack levels, and runs in 737 cycles (your code, after you add the missing branch instruction, uses 36 words of memory and runs in ~1360 cycles).

Code:
;******************************************************************
;  alternate bin2bcd  33 words, 737 cycles (147.4-us @20 MHz)     *
;******************************************************************

bin2bcd
        movlw   d'23'           ;
        movwf   countin         ; bit counter = 23
bcdadj
        movlw   0x33            ; Mike Keitz's "bcd adj" method
        addwf   lowbyte,F       ;
        btfsc   lowbyte,3       ; test if lo result > 7
        andlw   0xF0            ; lo result > 7 so take the 3 out
        btfsc   lowbyte,7       ; test if hi result > 7
        andlw   0x0F            ; hi result > 7 so ok
        subwf   lowbyte,F       ; any results <= 7, subtract back
        movlw   0x33            ; 
        addwf   midbyte,F       ;
        btfsc   midbyte,3       ; test if lo result > 7
        andlw   0xF0            ; lo result > 7 so take the 3 out
        btfsc   midbyte,7       ; test if hi result > 7
        andlw   0x0F            ; hi result > 7 so ok
        subwf   midbyte,F       ; any results <= 7, subtract back
        movlw   0x33            ; 
        addwf   highbyte,F      ;
        btfsc   highbyte,3      ; test if lo result > 7
        andlw   0xF0            ; lo result > 7 so take the 3 out
        btfsc   highbyte,7      ; test if hi result > 7
        andlw   0x0F            ; hi result > 7 so ok
        subwf   highbyte,F      ; any results <= 7, subtract back
        rlf     lowbyte,F       ; packed bcd digits 0 & 1
        rlf     midbyte,F       ; packed bcd digits 2 & 3
        rlf     highbyte,F      ; packed bcd digits 4 & 5
        bsf     PORTB,4         ; <clk> = '1'
        bcf     PORTB,4         ; <clk> = '0'
        bcf     lowbyte,0       ; 
        btfsc   PORTB,5         ; <dat> = '0'? yes, skip, else
        bsf     lowbyte,0       ; 
        decfsz  countin,F       ; last bit? yes, skip, else
        goto    bcdadj          ; process another bit
;
I'll try to take a look at the rest of your program as time permits.

Cheerful regards, Mike
 
Last edited:
hello every one here, and almost all r my seniors.. i am very very new to this all.. i m doing the cellfones repair and hav gud knowledge of chip level repair, but hav almost no knowledge of the assembly language, i hav done c programming by self study and still i m learning by my self due to sm reasons i can go to a institute to learn and doing self studies.. i want to learn the cpu programming and want to know that from where shud i start learning....i m learning the assemly also but due to self study i dont undestand a lots of things...like "movlw 0x33" this... i know perhaps this means move letral data 0x33 into the w register..perhaps.. i want to study.. plz giv me the reference from where i can learn and learn the assembly very deeply..
thanx in advance.. waiting for the reply...
 
the main problem is that how do i configure the display section with any pic..?????like nay matrix led display using the demuxes' how can i configure the display with a pic.. plz hlp me..
 
Wow Mike - I am so grateful!

Datasheet for the adc is found here: https://www.electro-tech-online.com/custompdfs/2012/06/24151fs.pdf

I see I made a typo with the p/n in my first post.

It's actually way more precise than what I was originally looking for (4.5 or 5 digit resolution), but whilst I was looking to find out what adc's are used in commercial bench meters I came across the 2415 mentioned as being used in one (sorry can't remember which) - sure enough Linear suggest 6 digit dvm's as an application, so I thought I'd use it.

Adding up the bits I get 7.5 digits, but the next digit only counts to 6 at FS. 6 digits is a nice size display and I don't need the 100nV resolution on the 2.5V range! (and I need to sort my ranges out properly anyway). That said, now you've got me to think about it, there's no reason to not make the data available and shift everything left for the lowest range.

I did wonder if the use of 'high' and 'low' was correct - I'd seen it applied to literals but couldn't see another way to do it with files, I thought I'd try it and see... Wish I'd thought of your way - seems so obvious now.

This is my first encounter with binary to bcd conversion, so I used the first thing I found that looked like it would suit, on the principle that it would be far better than anything I could write (being an assembler newbie, μC newbie and not a real programmer anyway). Turns out I banjaxed that, huh. Looking for some history on the routine you suggest I find you've been helping folks on the Microchip forums with this for quite a while too *wave*:D Anyway I'll probably use your routine, and have a go at writing my own to see if I don't make a hash of it.

Think I might start a blog on this, it's quite a major project for me.
 
Hi Pete

I used these tutorials on the 'net to get me started:
**broken link removed** (though I suspect it's not completely reliable)
**broken link removed**
http://www.microautomate.com/index.php

Since then I've had a pretty good idea of what I want to do, so just googled for specific things (like the binary to bcd conversion)

The core PIC instruction set (explains what each instruction does):
ww1.microchip.com/downloads/en/DeviceDoc/31029a.pdf

This was helpful:
http://talkingelectronics.com/projects/PICK A PIC Project/PICK-A-PIC Project.html
so is this:
**broken link removed**

There's lots of help to be found on the Microchip forums:
http://www.microchip.com/forums/

People will be more helpful the more information you give when you ask for help - that means code with comments, clear explanations of what you are trying to solve, diagrams where appropriate. Too many people post vague questions on forums and then get annoyed when no-one helps them (and it's annoying finding these questions, wanting to know the same thing, and not being able to see any answers!) Also, be polite, it goes a long way :)

As to your specific problem re a display - once you thoroughly understand multiplexing and demultiplexing the code shouldn't be hard to write. The code sample I included in my first post on this thread multiplexes a serial bcd output to 6 digits - don't take it as being good code though as I'm a newbie too!
 
For anyone that's interested in this (Mike?), I eventually realised that I need a multiplier to make the count from the ADC into a meaningful value, and also discovered (on another forum) that the 24 bit count of 16777216 is actually ±8388608 - should have spotted that, really. With a 5 volt reference, FSD for the meter will be ±2.5v. This resolves to a step size of little over 298nV - so the lowest meaningful reading has to be 1μV unless the meter has an amplifier at the input, hence 6 digits. So glad I understand that now even if the details are still a little fuzzy.

So for the record, what I wrote in my response on 3 June at 9.17pm is rubbish. I'm now trying to work out how best to scale the output.
 
Status
Not open for further replies.

Latest threads

Back
Top