Downloads

VACI - PIC16F877A Source Code & Hex Files (Proton PicBasic)
Download VACI_Hardware_Code___Hex_File.zip - 24.01 KB

VACI - User Interface Module (VB.Net)
Download VACI_PC.zip - 344.59 KB

My Windows CE App Tailored for the Lilliput PC745 and my Jeep. (Just as a sample)
Download JeepMind.zip - 343.32 KB

Introduction

The following document will provide information to develop your own VACI(Vehicle Accessory Computer Interface). What I have done is rather simple however it took about 3 weeks of planning, programming and Debugging. The wow factor on this interface is awesome; everyone that has seen/used the system wants one in their car. The system can also be modified to automate accessories.

Specifications

  • 2X RGB PWM Channels
  • 8X General Purpose Outputs
  • Support for 5 Channel AV switch. (7 Momentary Outputs)
  • RS232 Communication

Requirements

  • Software
    • Proton PicBasic Compiler
    • Serial Bootloader (Preferable)
    • VB.net
    • HyperTerminal
  • Hardware
    • PC
    • Pic16F877A
    • PicAllw Programmer (only needed if you do not have a Serial Bootloader on your PIC)
    • Olimex PIC-P40 Development board (20Mhz)
    • 3X ULN2803 Darlington arrays
    • Some 1,10,100uF capacitors to reduce noise.
    • RS232 Cable
  • Tools
    • Soldering Iron (required for ULN2803 and capacitors on Olimex P-40 Development Board)
    • Cutters
    • Oscilloscope(If you have one)

Schematic 

I'll Upload a proper schematic as soon as I get back home!  But for now, I think this should be enough to get anyone started!  If you have a Olimex PIC-40 Development board, you shouldn't need a schematic.  If you don't then you only need to build a stable 5V regulator and a RS232 logic level converter so that you can connect the serial of your computer to the serial of the microcontroller.  The other important thing is to have all your outputs connected to a ULN2803 Darlington Array IC and remember that the maximum load per output should not exceed 60mA. The ULN2803 is a sinking driver, so you are able to drive your 12V relays from 12VDC. 

Using the code

How the RGB software PWM works

In a nut shell, the RGB software PWM works through an infinite loop with a counter which resets after 255 (one Byte). Each color byte is then compared to the clock, if it is less than the clock the output is set high. If the color byte is greater than the clock byte the output is set to low. The color bytes are then changed through a serial data received interrupt.

I then placed the AV switch functions and General Purpose outputs, where the counter resets after reaching 255.

Proton PicBasic Code:

'****************************************************************
'* Name : SmartJeep.BAS *
'* Author : Marco van der Merwe *
'* Notice : Copyright (c) 2010 *
'* : All Rights Reserved *
'* Date : 8/21/2010 *
'* Version : 1.0 *
'* Notes : Test app for serial comms & RGB Controll *
'* : *
'****************************************************************


' PIC16F877 Pinout 



'                ----------------- 
'         MCLR -|1      |_|     40|- 
'        AvSAT -|2              39|- 
'        AvDVD -|3              38|- Interior Blue
'       AvCaTV -|4              37|- Interior Green 
'        AvVCR -|5              36|- Interior Red 
'        AvAux -|6       P      35|- Exterior Blue 
'      Av1/Av2 -|7       I      34|- Exterior Green
'       Av PWR -|8       C      33|- Exterior Red
'              -|9       1      32|- Vdd (5V)
'              -|10      6      31|- Vss (0V)
'     Vdd (5V) -|11      F      30|- GPIO 7
'      Vss(0V) -|12      8      29|- GPIO 6
'  Xtal(20Mhz) -|13      7      28|- GPIO 5
'  Xtal(20Mhz) -|14      7      27|- GPIO 4
'              -|15      A      26|- RS232(Rx)
'              -|16             25|- RS232(Tx)
'              -|17             24|- 
'              -|18             23|- 
'       GPIO 0 -|19             22|- GPIO 3
'       GPIO 1 -|20             21|- GPIO 2
'                ----------------- 




Device = 16F877A ' Select PIC16F877A for Destination Device
Declare Bootloader = On ' Notify Compiler of Bootloader 
Config HS_OSC ' Make use of High Speed Oscilator 
Xtal = 20 ' Use 20Mhz Xtal
Optimiser_Level = 1 ' Simple optimisation
Dead_Code_Remove = On ' Remove any redundant code

'Configure Hardware Serial Port 

Hserial_Baud = 9600 ' Set baud rate to 9600
Hserial_RCSTA = %10010000 ' Enable serial port and continuous receive
Hserial_Clear = On ' Optionally clear the buffer before receiving

'Disable Analog Ports
All_Digital true


'Serial Related Variables
Dim D_Index As Byte ' Char Rx index
Dim D_Byte[12] As Byte ' Rx buffer
Symbol RCIF = PIR1.5 ' Alias RCIF (USART Receive Interrupt Flag)



'Switch Vars
Dim AVclk As Byte
Dim AVMode As Byte
Dim GPO As Byte



'RGB Variables
Dim clk As Byte ' clk Counter

'Adjustabe Variables
Dim ERGB[3] As Byte 'Exterior Red, Green, Blue
Dim EBSO[3] As Byte 'Exterior Brightnes, Speed, Option
Dim IRGB[3] As Byte 'Interior Red, Green, Blue
Dim IBSO[3] As Byte 'Interior Brightnes, Speed, Option
'Important Note:
'EBSO & IBSO have not been fully implemented,
'they are put in place to support RGB effects and transitions


'---------------------------------------------------------------------------------------- 
' Initialise variables
DelayMS 500 ' Wait for the power supply to stabilise
INTCON = %11000000 ' Enable interrupts
On_Hardware_Interrupt GoTo SerialIn ' Declare harware interrupt handler routine
PIE1.5 = 1 ' Enable interrupt on USART
D_Index = 0 ' Initialise index as 0
clk = 0 ' Initialise Clk as 0
AVclk = 0 ' Initialise AVclk as 0
AVMode = 0 ' Initialise AVMode as 0
GPO = 0 ' Initialise GPO as 0
TRISB = %11000000 ' Set 0~5 on PortB as output for R1G1B1 R2G2B1 
TRISA = %11000000 ' Set 0~6 on PortA as output for AV Switch
TRISE = %11111110 ' Set 0 on portE as output for AV switch
TRISD = %00000000 ' Set 0~7 on PortD as output for General outputs


'Set all outputs to Low
PORTA = 0
PORTB = 0
PORTD = 0



Clear D_Byte ' Initialise D_Byte as 0 
Clear ERGB
Clear EBSO
Clear IRGB
Clear IBSO
'----------------------------------------------------------------------------------------
' Main Program
Loop: 
   ' Do the RGB PWM
   If clk < ERGB[0] Then
      Low PORTB.0
   Else
      High PORTB.0
   EndIf 
   If clk < ERGB[1] Then
      Low PORTB.1
   Else
      High PORTB.1
   EndIf 
   If clk < ERGB[2] Then
      Low PORTB.2
   Else
      High PORTB.2
   EndIf
   If clk < IRGB[0] Then
      Low PORTB.3
   Else
      High PORTB.3 
   EndIf
   If clk < IRGB[1] Then 
      Low PORTB.4
   Else
      High PORTB.4
   EndIf
   If clk < IRGB[2] Then
      Low PORTB.5
   Else
      High PORTB.5
   EndIf 


   Inc clk 'Increment the clock counter
   If clk >= 255 Then '
      clk = 0 ' Reset clk
      Inc AVclk ' Increment AVclk 
      If AVMode > 0 Then ' Check if AVMode has changed 
         Select Case AVMode
            Case <=32
               PORTA = AVMode
            Case 64
               High PORTE.0
         End Select
         AVMode = 0
         AVclk = 0 ' Reset AVclk
      EndIf
      PORTD = GPO
      If AVclk >= 32 Then ' On Duration
         PORTA = 0 ' Switch off
         PORTE = 0
         AVclk = 0 ' Reset AVclk
      EndIf
   EndIf 

   GoTo Loop



'---------------------------------------------------------------------------------------- 
' Interrupt handler
SerialIn: ' Buffer the character received
   Int_Sub_Start
INT#STARTH:
  Context Save 
RECHECK:
   If D_Index > 10 Then GoSub clr_Buff ' Max Index = 12

   HRSIn D_Byte[D_Index]
   HRSOut D_Byte[D_Index]



Inc D_Index ' Incement Buffer_Index

Select D_Byte[0]
      Case "A"
         If D_Index > 1 Then
            AVMode = D_Byte[1]
            GoSub clr_Buff
         EndIf
      Case "G"
         If D_Index > 1 Then
            GPO = D_Byte[1]
            GoSub clr_Buff
         EndIf 
      Case "E"
         If D_Index > 6 Then
            ERGB[0] = D_Byte[1]
            ERGB[1] = D_Byte[2]
            ERGB[2] = D_Byte[3]
            EBSO[0] = D_Byte[4]
            EBSO[1] = D_Byte[5]
            EBSO[2] = D_Byte[6]
            GoSub clr_Buff
         EndIf

      Case "I"
         If D_Index > 6 Then
            IRGB[0] = D_Byte[1]
            IRGB[1] = D_Byte[2]
            IRGB[2] = D_Byte[3]
            IBSO[0] = D_Byte[4]
            IBSO[1] = D_Byte[5]
            IBSO[2] = D_Byte[6]
            GoSub clr_Buff
         EndIf

      Case Else 
         GoSub clr_Buff
   End Select

   If RCIF = 1 Then RECHECK ' Check for another character while we're here
   GoTo INT_RETURN ' Return to program
   clr_Buff:
   D_Index = 0 ' Else Index 0
   Clear D_Byte ' Clear String
   Return
   INT#ENDH:
   INT_RETURN:
   Context Restore 
Int_Sub_End

Computer Interface Module

The Interface module then takes care of all the communication between the user interface and the microcontroller. Simply insert the following module in your VB.net Project.

VB.Net Module:

Imports System
Imports System.IO.Ports 'Support for serial Port control
Imports System.Drawing 'Support for color type


''' <summary>
''' Hardware communication module for VACI.
''' Created by Marco van der Merwe (7 September 2010)
''' </summary>
Module VACI
   WithEvents COMS As New SerialPort("Com1", 9600, Parity.None, 8, StopBits.One)
   '<<<< Serial Port >>>>
   ''' <summary>
   ''' Open Communication session
   ''' </summary>
   Sub Open()
      If COMS.IsOpen = False Then
         COMS.Encoding = System.Text.Encoding.Default
         COMS.Open() ' open the serial ComPort1
      End If
   End Sub



   ''' <summary>
   ''' Close Communication session
   ''' </summary>
   Sub Close()
     If COMS.IsOpen = True Then
        COMS.Close()
     End If
   End Sub



   Private Sub COMS_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles COMS.DataReceived
      Dim MyStr As String
      MyStr = COMS.ReadExisting
   End Sub



   '<<<< Hardware I/O Controll >>>>



   ''' <summary>
   ''' Lighting Effect Control
   ''' </summary>
   ''' <remarks></remarks>
   Class GlowFx
   
       ''' <summary>
       ''' Sets Exterior RGB Glow as Color
       ''' </summary>
       ''' <value></value>
       ''' <remarks></remarks>
       Shared WriteOnly Property Exterior() As Color
          Set(ByVal iColor As Color)
             If COMS.IsOpen = True Then
                 'Note that "000" is reserved for RGB Transitions and Effects 
                 COMS.Write("E" & Chr(iColor.R) & Chr(iColor.G) & Chr(iColor.B) & "000" & Chr(234)) 
             End If
          End Set
       End Property



       ''' <summary>
       ''' Sets Interior RGB Glow as Color
       ''' </summary>
       ''' <value></value>
       ''' <remarks></remarks>
       Shared WriteOnly Property Interior() As Color
          Set(ByVal iColor As Color)
             If COMS.IsOpen = True Then
                 'Note that "000" is reserved for RGB Transitions and Effects
                COMS.Write("I" & Chr(iColor.R) & Chr(iColor.G) & Chr(iColor.B) & "000" & Chr(234))
             End If
          End Set
       End Property
   End Class



    ''' <summary>
    ''' General I/O Control
    ''' </summary>
    ''' <remarks></remarks>
    Class GeneralIO
       Private Shared Switch(0 To 7) As Boolean
       Shared WriteOnly Property G0() As Boolean
         Set(ByVal G0 As Boolean)
            Switch(0) = G0
            SetGeneralIO()
         End Set
      End Property



      Shared WriteOnly Property G1() As Boolean
         Set(ByVal G1 As Boolean)
            Switch(1) = G1
            SetGeneralIO()
         End Set
      End Property



      Shared WriteOnly Property G2() As Boolean
         Set(ByVal G2 As Boolean)
            Switch(2) = G2
            SetGeneralIO()
         End Set
      End Property



      Shared WriteOnly Property G3() As Boolean
         Set(ByVal G3 As Boolean)
            Switch(3) = G3
            SetGeneralIO()
         End Set
      End Property



      Shared WriteOnly Property G4() As Boolean
         Set(ByVal G4 As Boolean)
            Switch(4) = G4
            SetGeneralIO()
         End Set
      End Property



       Shared WriteOnly Property G5() As Boolean
          Set(ByVal G5 As Boolean)
             Switch(5) = G5
             SetGeneralIO()
          End Set
      End Property

  

       Shared WriteOnly Property G6() As Boolean
          Set(ByVal G6 As Boolean)
             Switch(6) = G6
             SetGeneralIO()
          End Set
      End Property



       Shared WriteOnly Property G7() As Boolean
           Set(ByVal G7 As Boolean)
              Switch(7) = G7
              SetGeneralIO()
           End Set
      End Property



       Private Shared Sub SetGeneralIO()
          Dim GByte As Byte = 0
          GByte = IIf(Switch(0), 1, 0) + IIf(Switch(1), 2, 0) + IIf(Switch(2), 4, 0) + IIf(Switch(3), 8, 0) + _
          IIf(Switch(4), 16, 0) + IIf(Switch(5), 32, 0) + IIf(Switch(6), 64, 0) + IIf(Switch(7), 128, 0)
          If COMS.IsOpen = True Then
             COMS.Write("G" & Chr(GByte) & Chr(234))
          End If
       End Sub
   End Class



   ''' <summary>
   ''' AV Switch Control
   ''' </summary>
   ''' <remarks></remarks>
   Class AVSwitch


       ''' <summary>
       ''' Toggles AV Switch Power
       ''' </summary>
       ''' <remarks></remarks>
       Shared Sub TogglePWR()
          If COMS.IsOpen = True Then
             COMS.Write("A" & Chr(64) & Chr(234))
          End If
       End Sub



      ''' <summary>
      ''' Toggles AV Switch Output Channel
      ''' </summary>
      ''' <remarks></remarks>
      Shared Sub ToggleAV()
         If COMS.IsOpen = True Then
            COMS.Write("A" & Chr(32) & Chr(234))
         End If
      End Sub



      ''' <summary>
      ''' Sets AV Switch Channel: 1 through 5
      ''' </summary>
      ''' <param name="AVChan"></param>
      ''' <remarks></remarks>
      Shared Sub SetAVChan(ByVal AVChan As Byte)
         If COMS.IsOpen = True Then
            Select Case AVChan
               Case 1
                  COMS.Write("A" & Chr(1) & Chr(234))
               Case 2
                  COMS.Write("A" & Chr(2) & Chr(234))
               Case 3
                  COMS.Write("A" & Chr(4) & Chr(234))
               Case 4
                  COMS.Write("A" & Chr(8) & Chr(234))
               Case 5
                  COMS.Write("A" & Chr(16) & Chr(234))
            End Select
         End If
      End Sub


   End Class



End Module

To initialize the communication simply place the following code in your project, only remember to close the serial communication on exit. If you don't disable the serial communication when you exit the application there will be a problem initializing serial port if the application is reopened.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
   'Start Serial Communication with VACI
   VACI.Open()
End Sub

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
   'End Serial Communication with VACI
   VACI.Close()
End Sub



To toggle the power of the AV switch us the following code:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  VACI.AVSwitch.TogglePWR()
End Sub



To set the AV switch channel use the following code:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  VACI.AVSwitch.SetAVChan(1)
End Sub


The following code is used to set the General Purpose outputs G0 through G7, TRUE is for on and FALSE for off.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  VACI.GeneralIO.G3 = True
End Sub



The Following Code is used to set the RGB Glow Channel 1 as color:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  VACI.GlowFx.Exterior = Color.GreenYellow
End Sub


The Following Code is used to set the RGB Glow Channel 2 as color:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
   VACI.GlowFx.Interior = Color.OrangeRed
End Sub


Test

Points of Interest

I have been programming Pic16F's for over 7 years, and I got boared of manually flipping switches on my jeep. So I decided to combine my experiance of programming and hardware to develop this application to ease my accessory usage in my jeep.

My aim was to integrate all my accessories into a central system, I was given a Lilliput PC745 as a gift and decided to use that. In my solution I have used the PC745’s serial port to communicate with the PIC 16F877A.

The most complex problem that had to be solved is the 6 PWM (Pulse Width Modulation) channels that was needed to run the two RGB LED channels. The 16F877A only has two, so I opted for a type of software PWM. This meant that the first thing I had to get working was the software PWM along with the Serial communication.

This took several attempts with different resolutions, refresh rates and so on. I experimented with different clock frequencies. Finally it came to an 8bit resolution, with an unknown refresh rate. The best solution with the least amount of flicker came to be by doing an infinite loop with no delays and turning each of the pins on/off for the desired time.

The next task was to fit the General Purpose output pins in this infinite loop without delay, or else the RGB glow would flicker. The best way to do that is simply assign an entire port at the same time through one byte. So the PC would have to generate a Character for the desired pins to be switched on individually. Each bit in the byte is a pin on the microcontroller which makes life a bit easier.

I then had an off-the-shelf AV switch to select my AV input channels; it switches by momentary push button. So I combined PortE.0 with PortA, as PortA only has 6 pins and I needed 7. The tricky part was to create a momentary switch without delaying PWM channels. So to do this I stuck my code in at the end of the ForLoop that refreshes the RGB channels. So that it switches high at the end of the update, then waits for 32 RGB refresh cycles before clearing the port. This can be modified very easily to be used as General Purpose Outputs

History

First working version - 22/09/2010

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"