Single PIC to Blink 5 LEDs Independently?


Closed Thread
Results 1 to 40 of 69

Hybrid View

  1. #1


    Did you find this post helpful? Yes | No

    Default Re: Single PIC to Blink 5 LEDs Independently?

    Thanks Robert. 16Fs do make things easier for me. Looks like the 16F1782 has (4) 8bit timers and (1) 16bit timer so I'll pick up some of those.

    I'm wondering, though, if I could use a 12F683 (2 x 8-bit, 1 x 16-bit) and the unused ports of a 16F1825 (I have RC4 and RA3-5 ports available) which has 4 x 8-bit and 1 x 16-bit timers. Some of the TMRs on the 16F1825 are already used, I'm sure, since I'm using CCP1 & CCP2.

    How can I tell which TMRs are being used? Here's my code:

    Code:
    '****************************************************************
    '*  Name    : Nacelle_Motors_16F1825_32Mhz_Int_SN754410.pbp     *
    '*  Author  : Ross A. Waddell                                   *
    '*  Notice  : Copyright (c) 2012                                *
    '*          : All Rights Reserved                               *
    '*  Date    : 10/20/2012                                        *
    '*  Version : 2.0                                               *
    '*  Notes   : Motor control for TOS E engines using SN754110    *
    '*          : motor driver, plus steady-on amber lights         *
    '****************************************************************
    
    ' ***************************************************************
    ' TODOs
    ' ***************************************************************
    ' 1. Need to calibrate motor RPMs so they spin at the same rate
    '    -> Separate "MotorRPM" EEPROM variables?
    ' 2. Add power isolation as blinking running lights seem to increase electrical noise
             
    DEFINE OSC 32                ' Set oscillator 32 Mhz
    
    ' ***************************************************************
    ' Device Fuses
    ' ***************************************************************
    #CONFIG
       __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF
       __config _CONFIG2, _PLLEN_ON & _STVREN_ON & _BORV_LO & _LVP_OFF
    #ENDCONFIG
    
    ' ***************************************************************
    ' Initialization
    ' ***************************************************************
    
    OSCCON   = %11110000        ' 32 MHz internal osc (8 Mhz with 4x SPLLEN enabled)
    
    pause 100                   ' As advised by Darrel Taylor for EEPROM issue
    
    DEFINE CCP2_REG PORTC       ' Only need to define CCP2 pin as there are 2
    DEFINE CCP2_BIT 3           ' possible choices: RA5 or RC3
    
    PORTA    = 0                ' Set initial value of PORTA to 0
    PORTC    = 0                ' Set initial value of PORTC to 0
    ;ADCON0   = 7
    ;ADCON1   = 7
    ANSELA.0 = 0                ' Digital only on rotary encoder B pin
    ANSELA.1 = 0                ' Digital only on rotary encoder A pin
    ANSELA.2 = 0                ' Digital only on rotary encoder's button
    ANSELC.0 = 0                ' Digital only on Stbd motor direction signal (Motor 1)
    ANSELC.1 = 0                ' Digital only on Port motor direction signal (Motor 2)
    ANSELC.2 = 0                ' Digital only on LED_0 pin (steady-on amber lights)
    ANSELC.3 = 0                ' Digital only on CCP2 pin (Port engine)
    ANSELC.5 = 0                ' Digital only on CCP1 pin (Stbd engine)
    
    TRISA    = %00000111        ' Make PORTA pins 0-2 input for rotary encoder
    TRISC    = %00000000        ' Make all PORTC pins output
    
    ' The INTEDG bit of the OPTION_REG register determines on which edge the 
    ' interrupt will occur. When the INTEDG bit is set, the rising edge will 
    ' cause the interrupt. When the INTEDG bit is clear, the falling edge will 
    ' cause the interrupt. 
    OPTION_REG.6 = 1             ' 1=Rising edge (default) or button "PRESS";
                                 ' 0=Falling edge or button "RELEASE"
    
    Old_Bits       VAR BYTE
    New_Bits       VAR BYTE
    RotEncDir      VAR BIT       ' 1=CW, 0=CCW
                                 ' Rot Enc pin A connected to PortA.1;
                                 ' Rot Enc pin B connected to PortA.0
    Old_RPM        VAR BYTE
    I              VAR BYTE
    
    LED_0          VAR PORTC.2   ' Alias PORTC.2 as "LED_0"
    
    MOTOR_1_DIR    VAR PORTC.0   ' Alias PORTC.0 as "MOTOR_1_DIR"
    MOTOR_1_PWM    VAR PORTC.5   ' Alias PORTC.5 as "MOTOR_1_PWM"
    MOTOR_2_DIR    VAR PORTC.1   ' Alias PORTC.1 as "MOTOR_2_DIR"
    MOTOR_2_PWM    VAR PORTC.3   ' Alias PORTC.3 as "MOTOR_2_PWM"
    
    ButtonPress    VAR PORTA.2   ' Alias PORTA.2 as "ButtonPress"
    TimeCnt        VAR Word      
    
    LOW LED_0
    LOW MOTOR_1_DIR
    LOW MOTOR_1_PWM
    LOW MOTOR_2_DIR
    LOW MOTOR_2_PWM
    
    ' ***************************************************************
    ' Pin Connections
    ' ***************************************************************
    
    ' RA0                        -> B pin of rotary encoder
    ' RA1                        -> A pin of rotary encoder
    ' RA2                        -> Button switch pin of rotary encoder
    ' RC0                        -> Stbd motor direction signal (motor 1)
    ' RC1                        -> Port motor direction signal (motor 2)
    ' RC2                        -> Steady-on LED
    ' RC3/CCP2                   -> Port motor PWM output (motor 2)
    ' RC5/CCP1                   -> Stbd motor PWM output (motor 1)
    
    ' ***************************************************************
    ' Includes
    ' ***************************************************************
    
    INCLUDE "DT_INTS-14.bas"    ' Base Interrupt System
    INCLUDE "ReEnterPBP.bas"    ' Include if using PBP interrupts
                                ' --> copy both files to PBP main folder 
                                ' (i.e. c:\pbp3)
    INCLUDE "EE_Vars.PBP"       ' copy file to PBP main folder (i.e. c:\pbp3)
    
    ' ***************************************************************
    ' EEPROM Variables
    ' ***************************************************************
    
    MotorRPM VAR BYTE        :  @  EE_var        _MotorRPM, BYTE, 150
    PortEngDir VAR BYTE      :  @  EE_var      _PortEngDir, BYTE, 0
                                                                      
    ' ***************************************************************
    ' ASM Interrupt Definitions
    ' ***************************************************************
                                                                      
    ASM
    INT_LIST  macro    ; IntSource,            Label,  Type, ResetFlag?
            INT_Handler    IOC_INT,    _RotEncAdjust,   PBP,  yes
    ;        INT_Handler    INT_INT,  _RotEncBtnPress,   PBP,  yes
        endm
        INT_CREATE     ; Creates the interrupt processor
    ENDASM
    
    ' ***************************************************************
    ' Set default values
    ' ***************************************************************
    
    Old_RPM = MotorRPM
    Old_Bits = PORTA & (%00000011)
    
    HIGH LED_0                  ' Turn on steady-on LEDs
    
    LOW MOTOR_1_DIR             ' Set stbd motor (motor 1) to fwd (CW)
                                ' (always spins in the same direction)
    IF PortEngDir = 0 THEN
        LOW MOTOR_2_DIR         ' Set port motor (motor 2) to fwd (CCW)
    ELSE
        HIGH MOTOR_2_DIR        ' Set port motor (motor 2) to rev (CW)
    ENDIF
    
    ' Spin up motors to saved value of _MotorRPM
    ' (Below a cycle of 66, the motors don't move at all)
    IF MotorRPM > 66 THEN
        FOR I = 65 to MotorRPM
            pause 30             
            HPWM 1, I, 20000            ' Stbd engine (CCP1)
            IF PortEngDir = 0 THEN
                HPWM 2, I, 20000        ' Port engine (CCP2), fwd (CCW)
            ELSE
                HPWM 2, (255-I), 20000  ' Port engine (CCP2), rev (CW)        
            ENDIF
        NEXT I
    EndIf
    HPWM 1, MotorRPM, 20000             ' Stbd engine (CCP1)
    IF PortEngDir = 0 THEN              
        HPWM 2, MotorRPM, 20000         ' Port engine (CCP2)
    ELSE
        HPWM 2, (255-MotorRPM), 20000   ' Port engine (CCP2)
    ENDIF
    
    ' Enable interrupts on RPM control now that motors are fully spun up
    ;INTCON   = %10011000        ' Global int enabled, INTE enabled, IOCI enabled, 
                                ' INTF flag bit 0 clr, IOCI flag bit 0 clr
    INTCON   = %10001000        ' Global int enabled, IOCI enabled, 
                                ' INTF flag bit 0 clr, IOCI flag bit 0 clr
    IOCAP.0  = 1                ' Enable positive (rising edge) change
    IOCAP.1  = 1                ' Enable positive (rising edge) change
    IOCAN.0  = 1                ' Enable negative (falling edge) change
    IOCAN.1  = 1                ' Enable negative (falling edge) change
    IOCAF.0  = 0                ' Clear interupt-on-change flag
    IOCAF.1  = 0                ' Clear interupt-on-change flag
    ;INTCON.1 = 0                ' Clear RA2/INT External Interrupt Flag
    
    @ INT_ENABLE   IOC_INT      ; Interrupt-on-Change interrupt
    ;@ INT_ENABLE   INT_INT      ; INT/Ext Interrupt
    
    Main:
        ' Check if motor RPM has changed
        IF MotorRPM <> Old_RPM Then
            Old_RPM = MotorRPM
            GOSUB ChngMotorHPWM
        EndIF   
       
        TimeCnt = 0
    	While ButtonPress = 0
    	    TimeCnt = TimeCnt + 1
    	    Pause 10
    	    If TimeCnt > 500 Then BtnAction
    	Wend
     
        BtnAction:
            If TimeCnt > 0 and TimeCnt < 200 Then
                PortEngDir = PortEngDir + 1
                If PortEngDir > 1 Then PortEngDir = 0
    @ EE_write_var _PortEngDir        ; save the new number to EEPROM
                
                GOSUB ReversePortEng
            ElseIf TimeCnt >= 200 Then
    @ EE_write_default _MotorRPM        
            EndIf
     
        GOTO Main
    
    ReversePortEng:
        LOW MOTOR_2_DIR                    ' Electrically stop motor 2
        LOW MOTOR_2_PWM
    
        pause 100
    
        IF PortEngDir = 0 THEN
            LOW MOTOR_2_DIR                ' Set port motor (motor 2) to fwd (CCW)
        ELSE
            HIGH MOTOR_2_DIR               ' Set port motor (motor 2) to rev (CW)
        ENDIF
    
        IF PortEngDir = 0 THEN
            HPWM 2, MotorRPM, 20000        ' Port engine (motor 2), fwd (CCW)
        ELSE
            HPWM 2, (255-MotorRPM), 20000  ' Port engine (motor 2), rev (CW)    
        ENDIF
    
        RETURN
        
    
    ChngMotorHPWM:
        HPWM 1, MotorRPM, 20000  ' Stbd engine (motor 1)
                                 ; Tried 245 Hz but it made the motor too loud.
                                 ; Supposedly, anything above 20kHz is above 
                                 ; human hearing
    
        IF PortEngDir = 0 THEN
            HPWM 2, MotorRPM, 20000        ' Port engine (motor 2), fwd (CCW)
        ELSE
            HPWM 2, (255-MotorRPM), 20000  ' Port engine (motor 2), rev (CW)    
        ENDIF
        
        RETURN
    end
    
    ' ***************************************************************
    ' [IOC - interrupt handler]
    ' ***************************************************************
    RotEncAdjust:
        New_Bits = PORTA & (%00000011)
        IF (New_Bits & %00000011) = (Old_Bits & %00000011) Then DoneRotEnc
    
        RotEncDir = New_Bits.1 ^ Old_Bits.0
        IF RotEncDir = 1 Then
            ; CW rotation - increase speed but only to a max of 255
            IF MotorRPM < 255 then MotorRPM = MotorRPM + 1
        Else
            ' CCW rotation - decrease speed to a min of 0
            IF MotorRPM > 0 Then MotorRPM = MotorRPM - 1
        EndIF
    
    @ EE_write_var _MotorRPM        ; save the new number to EEPROM
    
    DoneRotEnc:
        Old_Bits = New_Bits
        
        IOCAF.0 = 0      ' Clear interrupt flags
        IOCAF.1 = 0
    
    @ INT_RETURN
    
    ' ***************************************************************
    ' [INT - interrupt handler]
    ' ***************************************************************
    ;RotEncBtnPress:
        ' Restore MotorRPM to default value
    ;@ EE_write_default _MotorRPM
    
    ;    INTCON.1  = 0    ' Clear RA2/INT External Interrupt Flag
    
    ;@ INT_RETURN
    Nacelle_Motors_16F1825_32Mhz_Int_SN754410_FINAL.txt

    Also, would adding the blinkies to this project (which already uses Darrel's DT_INST-14.bas to handle a quadrature rotary encoder inputs) affect the existing functionality?

  2. #2


    Did you find this post helpful? Yes | No

    Default Re: Single PIC to Blink 5 LEDs Independently?

    Do you see any (major) difference between the 16G1782 and the 16F1825? The latter has only 14 pins (compared to the former's 28) and that would help a lot; I only need 5 outputs. Plus, I have a bunch of those around.

    Ok, so let's say I use 1 dedicated 16F1825 chip to do the 5 independent blinks - should I use the SPWM include from Darrel? How do I configure the 5 timers with different on/off frequencies?

  3. #3
    Join Date
    May 2007
    Posts
    604


    Did you find this post helpful? Yes | No

    Default Re: Single PIC to Blink 5 LEDs Independently?

    Why pay for overpriced toys when you can have
    professional grade tools for FREE!!!

  4. #4
    Join Date
    May 2009
    Posts
    40


    Did you find this post helpful? Yes | No

    Default Re: Single PIC to Blink 5 LEDs Independently?

    You do not need a seperate hardware timer for each led. A single timer would do the job. Adapt the following code to suit your needs.
    Code:
    #config
      __CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_ON & _IESO_ON & _BOR_ON & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_ON & _XT_OSC
      __CONFIG    _CONFIG2, _WRT_OFF & _BOR40V
    #endconfig
    
    TIMER0  VAR  BYTE
    TIMER1  VAR  BYTE
    TIMER2  VAR  BYTE
    TIMER3  VAR  BYTE
    TIMER4  VAR  BYTE
    TIMER5  VAR  BYTE
    TIMER6  VAR  BYTE
    TIMER7  VAR  BYTE
     
    LED0   VAR  PORTB.0  
    LED1   VAR  PORTB.1  
    LED2   VAR  PORTB.2  
    LED3   VAR  PORTB.3  
    LED4   VAR  PORTB.4  
    LED5   VAR  PORTB.5  
    LED6   VAR  PORTB.6  
    LED7   VAR  PORTB.7  
    
    wsave    VAR  BYTE $70 SYSTEM
    ssave    VAR  BYTE $71 SYSTEM
    psave    VAR  BYTE $72 SYSTEM
    
    
    GOTO  START:
    DEFINE INTHAND MYINT
    ASM
    MYINT 
                movwf   wsave        ; <=2k codespace 
                swapf   STATUS,W     ; <=2k codespace
                clrf    STATUS       ; <=2k codespace
                movwf   ssave        ; <=2k codespace
                movf    PCLATH,W     ; <=2k codespace 
                movwf   psave        ; <=2k codespace
                TSTF    _TIMER0      ;test timer0
                BTFSS   STATUS,Z     ;skip if zero
                DECF    _TIMER0,F    ;decrement timer 0
                TSTF    _TIMER1
                BTFSC   STATUS,Z
                DECF    _TIMER1,F
                TSTF    _TIMER2
                BTFSC   STATUS,Z
                DECF    _TIMER2,F
                TSTF    _TIMER3
                BTFSC   STATUS,Z
                DECF    _TIMER3,F
                TSTF    _TIMER4
                BTFSC   STATUS,Z
                DECF    _TIMER4,F
                TSTF    _TIMER5
                BTFSC   STATUS,Z
                DECF    _TIMER5,F
                TSTF    _TIMER6
                BTFSC   STATUS,Z
                DECF    _TIMER6,F
                TSTF    _TIMER7
                BTFSC   STATUS,Z
                DECF    _TIMER7,F
                BCF     PIR1,0
                MOVF    psave,W
                MOVWF   PCLATH
                SWAPF   ssave,W
                MOVWF   STATUS
                SWAPF   wsave,F
                SWAPF   wsave,W
                RETFIE
    ENDASM
    
    START:
    ANSEL=0         'all pins are digital 
    ANSELH=0  
    TRISB=$00       'all outputs
    PORTB=0
    OPTION_REG=$80
    T1CON=$01       'interrupt every 65.5 ms
    PIE1=$01        'enable timer 1 interrupts
    INTCON=$C0      'enable interrupts
    AGAIN:
    IF TIMER0=0 THEN
       TIMER0=10
       TOGGLE LED0
    ENDIF
    IF TIMER1=0 THEN
       TIMER1=9
       TOGGLE LED1
    ENDIF
    IF TIMER2=0 THEN
       TIMER2=5
       TOGGLE LED2
    ENDIF
    IF TIMER3=0 THEN
       TIMER3=7
       TOGGLE LED3
    ENDIF
    IF TIMER4=0 THEN
       TIMER4=12
       TOGGLE LED4
    ENDIF
    IF TIMER5=0 THEN
       TIMER5=6
       TOGGLE LED5
    ENDIF
    IF TIMER6=0 THEN
       TIMER6=8
       TOGGLE LED6
    ENDIF
    IF TIMER7=0 THEN
       TIMER7=11
       TOGGLE LED7
    ENDIF
    GOTO AGAIN
    pic used is a 16F882.

  5. #5


    Did you find this post helpful? Yes | No

    Default Re: Single PIC to Blink 5 LEDs Independently?

    I will indeed try that out with a 1fF1825. Could you please clarify for me where I set the individual on/off values for each of the 8 LEDs? In my existing implementation (5 separate 12F683's) I have code like this:

    Code:
    ' Changing the value for "Cycle" will change the time it takes
    ' to fade from 100% to 0% (or 0% to 100% if duty is increasing)
    ' Lower number = faster fade in/out
    Cycle = 1
    
    ' Higher step value produces faster fade, but too high a value
    ' will introduce flicker
    STEP_CNTR = 2
    
    Main:
        ' Fade in
        For Duty = 0 TO 255 step STEP_CNTR
            PWM LED_0, Duty, Cycle
        Next
    
        ' Stay on LGHTS_ON_MS
        HIGH LED_0
        Pause LGHTS_ON_MS
    
        ' Fade out
        For Duty = 255 TO 0 STEP -STEP_CNTR
            PWM LED_0, Duty, Cycle
        Next
    	
        ' Stay off for LGHTS_OFF_MS
        Pause LGHTS_OFF_MS
    
        ' Fade in
        For Duty = 0 TO 255 step STEP_CNTR
            PWM LED_0, Duty, Cycle
        Next
    
        ' Stay on LGHTS_ON_MS
        HIGH LED_0
        Pause (LGHTS_ON_MS - 200)
    
        ' Fade out
        For Duty = 255 TO 0 STEP -STEP_CNTR
            PWM LED_0, Duty, Cycle
        Next
    	
        ' Stay off for LGHTS_OFF_MS
        Pause (LGHTS_OFF_MS + 100)
    
        GOTO Main
    (In actuality, I extend the fade in/stay on/fade out/stay off with various timings to randomize the effect. Old 1960's Christmas tree lights did not have constant blink rates).

  6. #6


    Did you find this post helpful? Yes | No

    Default Re: Single PIC to Blink 5 LEDs Independently?

    I've tried adapting Darrel's example from this thread, but no luck with a PIC16F1825 - PORTC.0-3 do not blink (PORTC.0-2 are off; PORTC.3 is on) but PORTC.4 blinks properly. What am I doing wrong here? I've had to adapt Darrel's code for the PIC16F1825 and reduced the number of blinkies to 5 from 8.

    Code:
    '****************************************************************
    '*  Name    : UNTITLED.BAS                                      *
    '*  Author  : Ross Waddell                                      *
    '*  Notice  : Copyright (c) 2012 [select VIEW...EDITOR OPTIONS] *
    '*          : All Rights Reserved                               *
    '*  Date    : 10/27/2012                                        *
    '*  Version : 1.0                                               *
    '*  Notes   : PIC16F1825                                                 *
    '*          :                                                   *
    '****************************************************************
    
    DEFINE OSC 4
    DEFINE BLINKYFREQ 100  ; 10mS periods
    
    ' ***************************************************************
    ' Device Fuses
    ' ***************************************************************
    ' PIC chip data sheets can be found here: C:\Program Files\Microchip\MPASM Suite
    #CONFIG
       __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF
       __config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF
    #ENDCONFIG
    
    OSCCON   = %01101000        ' 4MHz internal osc
    
    
    DATA 50,22,38,75,17;,40,62,13  ; default periods for each Output
    ;----------------------------------------------------------------
    CCPR1val  CON EXT      : @CCPR1val = (OSC*1000000/4)/ BLINKYFREQ
    CCPR1     VAR WORD EXT : @CCPR1 = CCPR1L
    Timer1    VAR WORD EXT : @Timer1 = TMR1L
    CCPIF     VAR PIR1.2
    
    LoopLED   VAR BYTE[5]
    LoopCON   VAR BYTE[5]
    x         VAR BYTE
    
    ;----[Initialize]------------------------------------------------
    FOR x = 0 to 4         ; load the periods from EEPROM
        READ x, LoopCON(x)
    NEXT X
    ;-- setup CCP1 and Start Timer1 --
    CCPR1   = CCPR1val     ; set compare value
    CCP1CON = %00001011    ; compare mode, special event 
    Timer1  = 0            ; clear Timer1
    T1CON.0 = 1            ; start Timer1
    
    ANSELC = 0
    TRISC = 0              ; PORTC all OUTPUT
    
    ;----[Main Program Loop]----------------------------------------
    Main: 
        ;x = (x + 1) // 8
        x = (x+1)&4
        PORTC.0(x) = !(LoopLED(x) < LoopCON(x))
        LoopLED(x) = (LoopLED(x) + 1) // (LoopCON(x) << 1)
        IF x != 4 THEN Main
    
    Waiting: IF !CCPIF THEN Waiting
        CCPIF = 0
    GOTO Main
    Last edited by RossWaddell; - 28th October 2012 at 18:35. Reason: correction

  7. #7


    Did you find this post helpful? Yes | No

    Default Re: Single PIC to Blink 5 LEDs Independently?

    Ok, so I answered my own question.

    This works:
    Code:
    x = (x + 1) // 5
    This doesn't:
    Code:
    x = (x+1)&4
    The question now becomes: is there a way to set the on/off periods individually for each of the 5 LEDs? The code above has the LEDs blink with the same on time as off; I need to be able to make some of the 'off' times longer than the 'on' and vice versa.
    Last edited by RossWaddell; - 28th October 2012 at 18:43.

Similar Threads

  1. Single button function
    By DynamoBen in forum mel PIC BASIC Pro
    Replies: 40
    Last Post: - 4th April 2020, 18:33
  2. How to blink 8 LEDs at different rates- concurrently?
    By rmteo in forum mel PIC BASIC Pro
    Replies: 14
    Last Post: - 26th April 2010, 23:47
  3. single sided PCB
    By schu4647 in forum General
    Replies: 1
    Last Post: - 10th December 2008, 18:22
  4. Can't Blink 2 LEDs
    By dfort in forum mel PIC BASIC
    Replies: 2
    Last Post: - 5th March 2008, 22:36
  5. Tx and Rx of Single Pin PIC's
    By Dwayne in forum Code Examples
    Replies: 0
    Last Post: - 26th May 2004, 14:55

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts