• 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.

Help with code modification

Thread starter #1
Hello,
I am working on a Larson scanner using an LED bar graph display in a prop build for a buddy. I have been an electronics hobbyist for decades now. I know my circuits, components and schematics, I'm just not a coder. I bread boarded the display using an ATTiny13A using code provided for public use on a blog site (the author is no longer monitoring his blog), loaded the code using a USB AVR programmer and it works great. There are just extra patterns in the code that I would like to eliminate as they are not needed. Also the code is set up for 12 LEDs and I would like to just use 10 as that is what is needed for the bar graph. I'm new here so I'm not sure if it ok to post the code from the ASM file.
 

atferrari

Well-Known Member
#2
Do not eliminate. It is just to feel better?

Not sure about those 10 instead 12 you mention. Could you elaborate?

The bargraph, what does it display, actually? Is there any numeric calculation for that?
 

Les Jones

Well-Known Member
#3
This is how to use code tags. I have inserted it as a picture so they will not be interpreted.

Screen Shot 02-27-17 at 10.38 PM.PNG
This is an example of using code tags
Code:
;
/*
 * Shutdown timer    (Shutdown_timer03)  (To shut off a light after a preset period and also if the battery voltage is too low.)
 *
 *  Created: 03/09/2015
 *   Author: Les
 *  Version 2 being modified by adding low battery warning light
 */
 ;   using ATTINY13
; Fuse bit settings
 ; Low           0x62   (0x6A is also OK)
 ; High        0xFF
 ; Extended    0xFF
 ; Lock           0xFF


 ;
;

;Use internal clock at 9.6 Mhz   (Default value) and divide by 8 by setting CKDIV8 fuse bit (These are the default setting on a new chip.)
; 9.6 Mhz/8 = 1.2 Mhz
;(So Instruction time = 833.3 nS)

; So for 50 uS delay requires 50/0.8333 = 60 instructions

; Burst needs to be 5 mS long. This will be 50 cycles of 10 Khz

;
;**************************************************************************
.nolist
.include   <tn13def.inc>   ; ATtiny 13
.list
.listmac

;***************************************************************************
;*
;* Global Register Variables
;*
;***************************************************************************
; Note register number is in decimal

.def   N200mS       = r17   ;Number of 200 mS
.def   Seconds       = r18   ;Number of seconds
.def   Minutes       = r19   ;Number of minutes
.def   count_L       = r22   ;Used for time delay
.def   Flags       = r23   ;Bit 0 used for battery low warning flag



.equ   Shutdown_volts   = 0xA4   ;battery voltage shutdown value. (164 decimal. Divide battery voltage using a 4.7K resistor to ground and a 10 K resistor to the )
;                                                                (collector ofthe power switching transistor. This gives a ratio of 0.32. So for a cut off voltage )
;                                                                (of 10.0 we need to detect 3.2 volts This is 256 x 3.2/5 = 164 )
.equ   Battery_Low   = 0xB4   ;Battery voltage low warning level. (Set to come on at 11.0 volts so this will be 1.0 * 0.32 = 3.52 volts at ADC input
;                                   (This will be a count of 256 * 3.52/5 = 180 = 0xB4 )
;
.equ   Shutdown_minutes = 5   ;Time to shutdown in minutes.
;
;
;******************************** INTERRUPT VECTORS ***********************
.CSEG
.ORG   00
       rjmp   reset
       reti
       reti
       rjmp    TC_overflow   ;Timer/Counter Overflow
       reti
       reti   ;   rjmp   timer1_OVF
       reti
       reti
       reti
       reti
;
;******************************* RESET *************************************
;   
; Initialise the stack-pointer   
reset:
               ldi   R16,low(RAMEND)
               out   SPL,R16


           
   

           
; initialize PORTB
;   Bit 0   Input    (pin 5)       (Input will be low when button is pressed.
;   Bit 1   Input
;   Bit 2   Input   ADC input (Pin 7)
;   Bit 3   Output  (Pin 2)   (Drive to low battery warning LED High for LED on)
;   Bit 4   Output   (Pin 3)   (Drive to power control tansistor base.)
;   Bit 5   Input

                   ldi   R16,0x18   ; Bits 3 and 4 as outputs.
                   out   DDRB,R16   ;
                   ldi   R16,0x10
                   out   PORTB,R16   ; PORTB Bit 3 low, bit 4 high


; initialize Flags
                   ldi Flags,0x00



;Initialize ADC

                   ldi R16,0x84           ;Enable ,  Prescale value 16,  No auto triggering
                   out ADCSRA,R16

                   ldi   R16,0b00000000
                   out   ADCSRB,R16

                   ldi R16,0x21   ;Select AD1 (pin 7) input, Select VCC as analogue reference. ADLAR (Left justify result)
                   out ADMUX,R16


                   ldi R16,0x04   ;Set PB2 as analoge input
                   out DIDR0,R16


;Initialize timer / counter


                   ldi R16,0x00           ;Normal operation
                   Out TCCR0A,R16

                   ldi R16,0x05           ;  Prescale value 1024 (Inc counter every 0.8333 uS x 1024 = 853.3 uS  (1171.88 hZ)
                   Out TCCR0B,R16           ; Counter will overflow every 218.445 mS  (4,58 hZ)  
                                           ; Counting to 234 would give 199.7 mS  ( 256 - 234 = 22 = 0x16)

                   ldi R16,0x02           ;TOIE0 (Bit1) : Timer/Counter0 Overflow Interrupt Enable
                   Out TIMSK0,R16

;Init time counters
                   ldi N200mS,0x05
                   ldi Seconds,0x00
                   ldi Minutes,0x00

;Wait for button to be released  (Wait for input to go high

Wait_Button_High:
                   sbis PINB,0
                   rjmp Wait_Button_High

                   bset 7       ;Enable global interrupst.

                   rjmp main


;Timer/Counter Overflow interrupt handler.
TC_overflow:

                   ldi R20,0x16       ;Preset timer so interrupt occures every 199.7 mS
                   out   TCNT0,R20

                   dec   N200mS ;200mS
                   breq TC01
                   RETI
TC01:
                   ldi N200mS,0x05


Inc_Sec:           

                   SBRS Flags, 0
                   CBI PORTB,0x03       ;Clear battery low warning LED
                   SBRS Flags,0       ;Bat_Warning   ;Skip if battery warning bit is set
                   RJMP Inc_S2

                   in R20,PORTB
                   ldi R21,0x08       ;Bits 3
                   eor R20,R21           ; Toggle bit 3 (Pin 2) (Every second)
                   out PORTB,R20




Inc_S2:
                   ldi R20,0x3C       ;60 decimal

                   inc   Seconds           ;Increment seconds counter
                   cpse Seconds,R20
                   rjmp TC_End
                   CLR Seconds

Inc_Min:
                   ldi R20,0x3C       ;60 decimal

                   inc   Minutes           ;Increment minute counter
                   cpse Minutes,R20
                   rjmp TC_End
                   CLR Minutes

TC_End:
                   RETI


;       ------------------------------------- End of interrupt handlers --------------------------------------




;
;                    Main program code
;
Main:
           nop
           nop
           ldi R20,Shutdown_minutes
           cpse Minutes,R20               ;Is it time to shutdown ?
           rjmp Not_Time
           cbi PORTB,4                       ;Clear PORTB bit 4
           rjmp End_Loop



Not_Time:
           nop
           nop
           nop
;           rjmp Main   ; Just loop waiting for interrupt


;Read ADC input value
                   ldi R16,0x84           ;Enable ,  Prescale value 16,  No auto triggering
                   out ADCSRA,R16

                   ldi R16,0x21   ;Select AD1 input (pin 7) Select VCC as analogue reference, ADLAR (Left justify result)
                   out ADMUX,R16

                   sbi   ADCSRA,ADSC      ; Start ADC conversion
                   nop
Wait_ADC_Ready:
                   sbic  ADCSRA,ADSC      ; Wait_ADC_Ready:
                   rjmp  Wait_ADC_Ready
                   in R20,ADCL           ;Read ADC result L  (Value not used but need to read this register befor high byte.)
                   in R20,ADCH           ;Read ADC result H

;Test for battery warning level
                   CBR Flags,0x01 ;Bat_Warning           ;Clear battery warning flag

                   CLC               ;Clear carry flag
                   SBCI R20,Battery_Low
                   BRBC 0x00,Test_Shutdown       ;Branch if carry bit is clear
                   SBR Flags,0x01 ;Bat_Warning           ;Set battery warning flag bit


;Test for battery shutdown level
Test_Shutdown:
                   in R20,ADCH           ;Read ADC result H again
                   CLC               ;Clear carry flag
                   SBCI R20,Shutdown_volts
                   BRBS 0x00,Bat_Low           ;Branch if carry bit is set
                   RJMP Bat_OK

Bat_Low:
                   CBI PORTB,0x04           ; Shutdown

End_loop:
                   NOP
                   RJMP End_loop           ; Loop until power removed.



Bat_OK:


Test_button:                           ;If button pressed input will be low.
                   sbic   PINB,0

                   rjmp Main   ; Just loop waiting for interrupt

;Now wait 100 mS and recheck that button is pressed. (De bounce switch contacts)
                   rcall Delay_100ms
                   sbic   PINB,0   
                   rjmp Main
                   cbi PORTB,4                       ;Clear PORTB bit 4
                   rjmp End_Loop








;Test_button:
                   sbis   PINB,0
                   rjmp   Test_button   ;Loop until button pressed

;Now wait 100 mS and recheck that button is pressed. (De bounce switch contacts)
                   rcall Delay_100ms
                   sbis   PINB,0   
                   rjmp   Test_button   ;Loop until button is pressed


Button_open_loop:
                   sbic   PINB,0   ;
                   rjmp   Button_open_loop; loop until pedal released








;Subroutines.
;
;
;                               ----------------------------------------------
; Instruction cycle time is 0.83333 uS

; Delay 1mS  Rcall to get here takes 3 instruction cycles. ret instruction takes 4 instruction cycles, ldi takes 1 instruction cycle (total 8)

; For 1 mS (1000 uS) we need 1000/0.83333 = 1200 instructions  so need additional 1192 instructions    5 cycles in loop.


Delay_1_mS:
                   ldi    count_L,0xEE   ;Decimal 238  0xEE (Once round the loop is 5 instructions)
D_1mS_Loop:
                   dec   count_L       ; Count_L is R22  (1 cycle)
                   nop               ;(1 cycle)
                   nop               ;(1 cycle)
                   brne    D_1mS_Loop   ;If not zero  (2 cycles while looping, 1 on exit)
                   ret





Delay_100ms:
                   ldi R21,0x64   ;100 decimal
Del_100ms_Loop:
                   rcall Delay_1_mS
                   dec R21
                   brne Del_100ms_Loop
                   ret

;                               -------------End of subroutines --------------
;
Les.
 
Thread starter #4
Do not eliminate. It is just to feel better?
Not sure about those 10 instead 12 you mention. Could you elaborate?
The bargraph, what does it display, actually? Is there any numeric calculation for that?
atferrari, I need to get rid of unused code, only need the bargraph to use one function of the code. Circuit wise, I can get by with using all 12 segments instead of 10, I can work around that with little to no issue. This is a 10 segment LED bargraph running a larson scanner (knight rider style). I am only using 3 components for the prop as space is a major issue. Parts; 10 segment LED bargraph, ATTiny13A and a 10K pot to vary the speed, once the correct speed is obtained, will replace pot with a fixed resistor.

This is the code from the asm file. From what I can tell from the code, all I need is mode, 0 as this is the effect my buddy is going for. I don't need the rest of the LED pattern functions. I wanted to trim mode1, mode2 & mode3 from the code, but am unsure how to so without affecting mode, 0 operation.

Code:
/*********************************************************
                                                     
 CharlieScanner

 Software to generate a Larson scanner pattern on 12 LEDs
 Charlieplexing is used in order to control the LEDs with
 only 4 IO ports. One port reads in a voltage. The
 software then changes speed accordingly.

 Uses internal RC-Osc at 9.6 MHz/8
 Fuses should be set to default

 Written by Thomas Frey    http://tomscircuits.blogspot.com/

 $Date:$

*********************************************************/

; defines

#define tmp        R16
#define    tmp2        R17
#define duration    R18
#define LED        R19
#define adc_result    R20
#define mode        R21


#include "tn13def.inc"

.MACRO LEDon
    ldi    LED, @0
    rcall    setled
.ENDMACRO


.cseg


/*********************************************************

 Interrupt vectors

*********************************************************/
.org 0    rjmp reset
         


.org    INT0addr         rjmp reset        ;External Interrupt0
.org    PCI0addr       rjmp reset        ;Pin Change Interrupt0
.org    OVF0addr     rjmp reset        ;Overflow0 Interrupt 
.org    ERDYaddr         rjmp reset        ;EEPROM write complete
.org    ACIaddr        rjmp reset        ;Analog Comparator Interrupt 
.org    OC0Aaddr    rjmp reset        ;Timer/Counter0 Compare Match A    
.org    OC0Baddr    rjmp reset        ;Timer/Counter0 Compare Match B    
.org    WDTaddr            rjmp reset        ;Watchdog Timeout
.org    ADCCaddr         rjmp reset        ;ADC Conversion Complete Handle






/*********************************************************

 Initialisation

*********************************************************/
reset:

; set stack pointer
    ldi    tmp, LOW(RAMEND)
    out    SPL, tmp


; set clock to 1,2 MHz
   
    ldi    tmp, 0b10000000
    out    CLKPR, tmp

    ldi    tmp, 0b00000011        ; Divide by 8
    out    CLKPR, tmp


; init ADC

    ldi    tmp, (1<<ADLAR)|(1<<MUX1)    ; Use ADC in 8bit mode, PB4; Vcc is reference
    out    ADMUX, tmp

    ldi    tmp, (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN)    ; Slow conversion, ADC on
    out    ADCSRA, tmp

    rjmp    main

; init registers
    ldi    mode, 0



/*********************************************************

 Main loop

*********************************************************/

main:

    cpi    mode,0
    brne    mode1

    LEDon 1
    LEDon 2
    LEDon 3
    LEDon 4
    LEDon 5
    LEDon 6
    LEDon 7
    LEDon 8
    LEDon 9
    LEDon 10
    LEDon 11
    LEDon 12

    LEDon 11   
    LEDon 10
    LEDon 9
    LEDon 8
    LEDon 7
    LEDon 6
    LEDon 5
    LEDon 4
    LEDon 3
    LEDon 2

    rjmp    main

mode1:

    cpi    mode, 1
    brne    mode2

    LEDon 1
    LEDon 2
    LEDon 3
    LEDon 4
    LEDon 5
    LEDon 6
    LEDon 7
    LEDon 8
    LEDon 9
    LEDon 10
    LEDon 11
    LEDon 12

    rjmp    main

mode2:
    cpi    mode, 2
    brne    mode3

    LEDon 1
    LEDon 12

    LEDon 2
    LEDon 11

    LEDon 3
    LEDon 10

    LEDon 4
    LEDon 9

    LEDon 5
    LEDon 8

    LEDon 6
    LEDon 7

    LEDon 7
    LEDon 6

    LEDon 8
    LEDon 5

    LEDon 9
    LEDon 4

    LEDon 10
    LEDon 3

    LEDon 11
    LEDon 2

    LEDon 12
    LEDon 1


    rjmp    main

mode3:

    LEDon 1
    LEDon 2
    LEDon 1
    LEDon 3
    LEDon 2
    LEDon 4
    LEDon 3
    LEDon 5
    LEDon 4
    LEDon 6
    LEDon 5
    LEDon 7
    LEDon 6
    LEDon 8
    LEDon 7
    LEDon 9
    LEDon 8
    LEDon 10
    LEDon 9
    LEDon 11
    LEDon 10
    LEDon 12
    LEDon 11
    LEDon 12


    rjmp    main


/*********************************************************

    Sub routine:    wait

    Function:    Generates a pause, depending on ADC
            input

    Parameter: none / duration - lenght of the pause
   
*********************************************************/

wait:
    sbi     ADCSRA, ADSC        ; start ADC conversion
   
wait_adc:
    sbic    ADCSRA, ADSC        ; wait for the ADC to finish
    rjmp    wait_adc

    in    adc_result, ADCH

    tst    adc_result
    brne    wait_cont        ; not minimum? -> go on
   
                    ; else: change mode
    inc    mode
    andi    mode, 0b00000011    ; wrap around (four modes only)

wait_endmode:
    sbi     ADCSRA, ADSC        ; start ADC conversion
   
wait_adc2:
    sbic    ADCSRA, ADSC        ; wait for the ADC to finish
    rjmp    wait_adc2

    in    adc_result, ADCH

    tst    adc_result
    breq    wait_endmode

wait_cont:
    mov    duration, adc_result
    inc    duration

    ldi    tmp, 0
   
timer_loop:

    dec    tmp
    brne    timer_loop

    dec    duration
    brne    timer_loop

    ret



/*********************************************************

    Sub routine:    setled

    Function:    switches one LED on and waits

    Parameter:    LED - which LED to activate
            0 means none
   
*********************************************************/


setled:

    rcall    setport

    ldi    tmp, 250
    rcall    wait

    ret


/*********************************************************

    Sub routine:    setport

    Function:    switches one LED on

    Parameter:    LED - which LED to activate
            0 means none
   
*********************************************************/

setport:

    clr    tmp

    ldi    ZL, LOW(translation*2)
    ldi    ZH, HIGH(translation*2)

    lsl    LED            ; LED * 2 - for LPM instruction

    add    ZL, LED
    adc    ZH, tmp

    lpm    tmp, Z+
    out    DDRB, tmp

    lpm    tmp, Z
    out    PORTB, tmp

    ret


translation:
    .db    0b00000000, 0b00000000

    .db    0b00000011, 0b00000001
    .db    0b00000101, 0b00000001
    .db    0b00001001, 0b00000001

    .db    0b00000011, 0b00000010
    .db    0b00000110, 0b00000010
    .db    0b00001010, 0b00000010

    .db    0b00000101, 0b00000100
    .db    0b00000110, 0b00000100
    .db    0b00001100, 0b00000100

    .db    0b00001001, 0b00001000
    .db    0b00001010, 0b00001000
    .db    0b00001100, 0b00001000
 

Pommie

Well-Known Member
Most Helpful Member
#5
Remove the first two lines after main and all the code from mode0: to the comments above the subroutine wait.

Mike.
Edit, so your main loop looks like this,
Code:
/*********************************************************

 Main loop

*********************************************************/

main:
    LEDon 1
    LEDon 2
    LEDon 3
    LEDon 4
    LEDon 5
    LEDon 6
    LEDon 7
    LEDon 8
    LEDon 9
    LEDon 10
    LEDon 11
    LEDon 12

    LEDon 11  
    LEDon 10
    LEDon 9
    LEDon 8
    LEDon 7
    LEDon 6
    LEDon 5
    LEDon 4
    LEDon 3
    LEDon 2
    rjmp    main

/*********************************************************

    Sub routine:    wait

    Function:    Generates a pause, depending on ADC
            input

    Parameter: none / duration - lenght of the pause
   
*********************************************************/
 
Thread starter #6
Thank you Mike! I appreciate you taking the time and effort to look it over. Will give a go after work this evening and compile it to hex. I will let you know how it goes, again, much thanks!
 
Thread starter #7
So with Mike's help I got the code changed. I'm using Atmel Studio 6.2 to try and compile the ASM file. Did a bit of research on how to use AS. What I can't find is when I start a project, do I need to use GCC C executable or static library project or the GCC C++ version(s). I've tried both executable and static library can get the code to build but get an error with #include "tn13def.inc" saying no such file or directory. I see the tn13def.inc file is in the include folder for Atmel Studio so I figure it may be a syntax issue with the include? Any help would be greatly appreciated.
 

Les Jones

Well-Known Member
#8
You are not compiling "C" code. When you start a new project there should be an option to use Atmel AVR assembler. Select that option.

Les.
 
Thread starter #10
Again, I wish to thank you Mike & Les for lending a hand. I really appreciate your help. Got everything working like it should. Couldn't have done so without your generosity. If you ever need help with anything on the electronic side of things, please let me know, I would like to return the favor.
 

Les Jones

Well-Known Member
#11
I'm pleased that everyting is now working. It was a pleasure helping. We get too many posts where the OP does not give any information about the problem and the thread has many posts before we know what the question really is.

Les.
 

Latest threads

EE World Online Articles

Loading

 
Top