久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 7371|回復: 1
打印 上一主題 下一主題
收起左側

使用PIC12F683單片機構建簡單激光投影儀

[復制鏈接]
跳轉到指定樓層
樓主
翻譯+轉載作品:使用Microchip PIC12F683單片機構建自己的簡單激光投影儀
2010413日,作者:rwb,隸屬于Microcontroller


8引腳PIC12F683單片機是Microchip 8位單片機系列中最小的成員之一,但具有強大的外設,例如ADCPWM功能。這使得這個微型微控制器適用于控制直流電動機的速度。為了演示PIC12F683的功能并使本教程更具吸引力,我決定使用PIC12F683微控制器通過廉價的鑰匙串激光筆生成簡單而又引人入勝的激光表演。
在許多娛樂俱樂部或公園中顯示的激光燈基本都使用兩種方法。第一個是在觀眾身上發射激光束,第二個是在屏幕上顯示激光繪圖圖案。在本教程中,我們將使用微型Microchip PIC12F683微控制器構建激光投影儀,在屏幕上顯示呼吸描記器圖案。
制作呼吸描記器激光投影儀的原理是至少使用兩個直流電機,并在其上安裝反射鏡,然后這些反射鏡會將激光束從一個直流電機反射鏡偏轉到第二個直流電機反射鏡,最后偏轉到屏幕。通過控制每個直流電動機的旋轉速度,我們可以在屏幕上生成引人入勝的激光呼吸描記器圖案,如下圖所示。
控制直流電動機速度的最佳方法是使用PWM(脈沖波調制)信號來驅動直流電動機,并且由于我們要手動更改直流電動機速度,因此我們需要使用微調端口或電位計來控制每個直流電動機。直流電動機的速度。嗯,這聽起來像是微控制器的一項適當工作,但我們可以使用這種8引腳微型PIC12F683微控制器來完成此任務嗎?
從數據表中您會注意到,Microchip PIC12F683單片機只有一個PWM輸出(CCP1)和四個ADC輸入通道(AN0AN1AN2AN3)。由于我們需要兩個PWM輸出,因此在本教程中,我將向您展示如何基于PIC12F683單片機TIMER0外設生成PWM信號,而不是使用內置在PWM外設中的PIC12F683單片機。以下是激光投影儀項目的完整電子原理圖。
好吧,在我們進一步介紹細節之前;讓我們列出完成此激光投影儀項目所需的支持外圍設備:

  • 熱膠槍
  • 鑰匙串激光筆或任何可用的激光筆
  • 3xAA4.5伏電池座,用于為激光指示器供電,請使用與激光指示器相同的電壓速率。
  • 從廢棄的PS2雙電擊操縱桿中取出兩個直流電機
  • 來自田宮賽車的兩個玩具車輪胎
  • 鏡子的CD / DVD,用廚房剪刀將CD / DVD切成直徑約38毫米的兩個圓形鏡子
  • 一些用于固定直流電動機的玩具塑料積木
  • 面包板
  • 激光投影儀的底座使用硬板或丙烯酸樹脂
  • 雙面膠帶
以下是我用于制作此激光投影儀項目的電子零件和軟件開發工具:

  • 電阻器:3303),1K5)和10K1
  • Trimport10K2
  • 電容:100nF2)和10nF1
  • 一個100uH電感器
  • 兩個1N4148二極管
  • 兩個藍色和一個紅色發光二極管(LED
  • 兩個2N2222A晶體管
  • 一個迷你按鈕開關
  • 一個Microchip     PIC12F683單片機
  • Microchip MPLAB v8.46 IDE(集成開發環境)
  • Microchip宏匯編器MPASMWIN.exe     v5.35mplink.exe     v4.35
  • PIC10 / 12/16 MCUHI-TECH C編譯器(精簡模式)V9.70
  • Microchip PICKit3編程器(固件套件版本:01.25.20
該項目的目標是為持續教訓我以前發布博客介紹PIC匯編語言部分-1介紹PIC匯編語言部分-2,所以我用的第2部分呈現相同的PIC12F683板,你可以降負荷兩者的以EagleCAD格式設計的電子原理圖和PCB布局。該激光投影儀項目的另一個有趣特征是:除了PIC匯編代碼外,我還為C語言愛好者提供了該項目的C語言版本,并使用HI-TECH C編譯器進行了編譯(最近HI-TECH軟件已被Microchip收購)。此C語言版本可用于學習以及嵌入式系統編程語言比較。
在該項目中,我還使用了一個新的Microchip PICKit3編程器,但是您當然可以使用Microchip PICKit2編程器將十六進制代碼下載到PIC12F683單片機閃存中。
以下是PIC匯編語言中的Laser Projector代碼:
;******************************************************************************
; File Name    : laserlight.asm
; Version      : 1.0
; Description  : Laser Light ShowProject
; Author       : RWB
; Target       : Microchip PIC12F683Microcontroller
; Compiler     : Microchip Assembler(MPASMWIN.exe v5.35, mplink.exe v4.35)
; IDE          : Microchip MPLAB IDEv8.46
; Programmer   : PICKit3 (FirmwareSuite Version: 01.25.20)
; Last Updated : 01 April 2010
; *****************************************************************************
#include <p12F683.inc>
__config (_INTRC_OSC_NOCLKOUT &_WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF &_FCMEN_OFF)
#define MAX_TMR0 0xFB
#define MAX_COUNT .200
#define MAX_DEBOUNCE 0x0A
#define MAX_TBLINDEX 0x0A
; Define variables used
    cblock 0x20
Delay:2                      ; Define two registersfor the Delay and Delay + 1
mode                         ; Operation Mode
pwm_count                    ; Hold the Main PWM Counter
pwm_m1                      ; Hold the PWMwidth for Motor 1
pwm_m2                       ; Hold the PWM width forMotor 2
keycount                     ; Debounce Count
tableindex                   ; Table Index for Auto PWM
    endc
; Define variable use for storing STATUSand WREG register
    cblock 0x70             ; Useunbanked RAM, available both in Bank0 and Bank1
saved_w
saved_status
    endc
; Start the Light show Assembler Code here
    org 0x00                ; Wealways start at flash address 0
    goto Main               ; Jump toMain
    org 0x04                ; 0x04:Start PIC Interrupt Address
PIC_ISR:                     ; Start the PIC InterruptService Routine
    movwf   saved_w         ; Save Working Register
    movf    STATUS,w        ; Save Status Register
    movwf   saved_status
; Check the TIMER0 Interrupt here
    btfss   INTCON,T0IF
    goto    ExitISR         ; If (T0IF != 1) then Exit ISR
    bcf     STATUS,RP0      ; Select Registers at Bank 0
    incf    pwm_count       ; pwm_count++
    movlw   MAX_COUNT
    subwf   pwm_count,w     ; if (pwm_count < MAX_COUNT) thenCheckPWM
    btfss   STATUS,C        ; else clear GP1 and GP2
    goto    CheckPWM
    bcf     GPIO,GP1        ; GPIO1=0
    bcf     GPIO,GP2        ; GPIO2=0
    goto    ExitPWM
CheckPWM:
    movf    pwm_m1,w
    subwf   pwm_count,w
    btfsc   STATUS,Z        ; if (pwm_count == pwm_m1) then Set GP1
    bsf     GPIO,GP1        ; Set GP1 Bit
CheckM2:
    movf    pwm_m2,w
    subwf   pwm_count,w
     btfsc   STATUS,Z        ; if (pwm_count == pwm_m2) then Set GP2
    bsf     GPIO,GP2        ; Set GP2 bit
ExitPWM:
    bcf     INTCON,T0IF     ; clear the TIMER0 interrupt flag
    movlw   MAX_TMR0
    movwf   TMR0            ; TMR0 = MAX_TMR0
ExitISR:
    movf    saved_status,w
    movwf   STATUS          ; Restore STATUS Register
    swapf   saved_w,f
    swapf   saved_w,w       ; Restore W Register
    retfie                  ; Returnfrom Interrupt
Main:
    bsf     STATUS,RP0      ; Select Registers at Bank 1
    movlw   0x70
    movwf   OSCCON          ; Set the internal clock speed to 8MHz
    movlw   0x39            ; GP1 and GP2 Output, GP0,GP3,GP4and GP5 as Input
    movwf   TRISIO          ; TRISIO = 0x39        

    bcf     STATUS,RP0      ; Select Registers at Bank 0
    movlw   0x07
    movwf   CMCON0          ; Turn off Comparator (GP0, GP1, GP2)
    clrf    GPIO

; Now we Set the ADC Peripheral
    bsf     STATUS,RP0      ; Select Registers at Bank 1
    movlw   0x79            ; Set AN0 (GP0) and AN3 (GP4) asAnalog Input
    movwf   ANSEL           ; Using the Internal Clock(FRC)  

; Now we set the TIMER0 Peripheral
; TIMER0 Period = 1/FSOC x 4 x Prescale xTMR0
    movlw   0x00            ; Use TIMER0 Prescaler 1:2, InternalClock
    movwf   OPTION_REG      ; OPTION_REG = 0x00
    bcf     STATUS,RP0      ; Select Registers at Bank 0
    movlw   MAX_TMR0
    movwf   TMR0            ; TMR0=MAX_TMR0      

; Initial the variables used
    clrf    mode            ; Default mode = 0, Light Show Off
    clrf    pwm_count       ; pwm_count = 0
    clrf    pwm_m1          ; pwm_m1 = 0
    clrf    pwm_m2          ; pwm_m2 = 0
    clrf    keycount        ; keycount = 0
    clrf    tableindex      ; tableindex = 0
; Activate the Interrupt
    bsf     INTCON,GIE      ; Enable Global Interrupt
MainLoop:
    btfsc   GPIO,GP5        ; Now we check the Button
    goto    CheckMode       ; if (GP5 != 0) goto CheckMode
    movlw   0x01
    addwf   keycount        ; keycount=keycount + 1
    movf    keycount,w
    sublw   MAX_DEBOUNCE
    btfss   STATUS,C        ; if (keycount > MAX_DEBOUNCE) gotoKeyPressed
    goto    KeyPressed
    goto    CheckMode       ; else CheckMode
KeyPressed:
    clrf    keycount        ; keycount=0
    incf    mode            ; mode++
    movlw   0x03
    subwf   mode,w          ; W = mode - 0x03
    btfsc   STATUS,C        ; if (mode >= 0x03)
    clrf    mode            ; mode=0;
    movlw   0x01            ; else check the mode
    subwf   mode,w
    btfss   STATUS,C        ; if (mode >= 0x01) goto TurnOn
    goto    TurnOff         ; else goto TurnOff
    goto    TurnOn
TurnOff:
    bcf     INTCON,T0IE     ; Disable TIMER0 Interrupt
     clrf    pwm_count       ; pwm_count = 0
    clrf    pwm_m1          ; pwm_m1 = 0
    clrf    pwm_m2          ; pwm_m2 = 0
    bcf     GPIO,GP1
    bcf     GPIO,GP2
    movlw   .250
    call    DelayMs         ; DelayMs(250)
    movlw   .250
    call    DelayMs         ; DelayMs(250)
    goto    CheckMode
TurnOn:
    bsf     INTCON,T0IE     ; Enable TIMER0 Interrupt                    

CheckMode:
    movlw   0x01
    subwf   mode,w
    btfss   STATUS,Z        ; if (mode == 1) goto ShowMode1
     goto   CheckMode2
    goto    ShowMode1
CheckMode2:
    movlw   0x02
    subwf   mode,w
    btfss   STATUS,Z        ; if (mode == 2) goto ShowMode2
    goto    KeepLoop
    goto    ShowMode2
ShowMode1:                   ; Used ADC for PWM
     movlw   B'00000001'     ; Left Justify and turn on the ADCperipheral, channel 0 (AN0)
    movwf   ADCON0          ; Vreff=Vdd
    bsf     ADCON0,GO       ; Start the ADC Conversion on channel 0(AN0)
    btfss   ADCON0,GO       ; while(GO == 1)
    goto    $-1             ; Keep Loop
    call    Delay1ms
    movlw   B'00000001'     ; Left Justify and turn on the ADCperipheral, channel 0 (AN0)
    movwf   ADCON0          ; Vreff=Vdd
    bsf     ADCON0,GO       ; Start the ADC Conversion on channel 0(AN0)
    btfss   ADCON0,GO       ; while(GO == 1)
    goto    $-1             ; Keep Loop
    movf    ADRESH,w        ; Conversion Done, Read ADRESH
    movwf   pwm_m1          ; pwm_m1 = ADRESH
    call    Delay1ms

    movlw   B'00001101'     ; Left Justify and turn on the ADCperipheral, channel 3 (AN3)
    movwf   ADCON0          ; Vreff=Vdd
    bsf     ADCON0,GO       ; Start the ADC Conversion on channel 3(AN3)
    btfss   ADCON0,GO       ; while(GO == 1)
    goto    $-1             ; Keep Test
    call    Delay1ms
    movlw   B'00001101'     ; Left Justify and turn on the ADCperipheral, channel 3 (AN3)
    movwf   ADCON0          ; Vreff=Vdd
    bsf     ADCON0,GO       ; Start the ADC Conversion on channel 3(AN3)
    btfss   ADCON0,GO       ; while(GO == 1)
    goto    $-1             ; Keep Test
    movf    ADRESH,w        ; Conversion Done, Read ADRESH
    movwf   pwm_m2          ; pwm_m2 = ADRESH
    call    Delay1ms
    goto    KeepLoop
ShowMode2:                   ; Used Predefined Value forPWM
    movf    tableindex,w
    call    tablepwm1       ; Call tablepwm1
    movwf   pwm_m1          ; Assigned it to pwm_m1
    movlw   .30
    call    DelayMs         ; DelayMs(30)

    movf    tableindex,w
    call    tablepwm2       ; Call tablepwm2
    movwf   pwm_m2          ; Assigned it to pwm_m2
    movlw   .30
    call    DelayMs         ; DelayMs(30)
    incf    tableindex      ; tableindex++
    movlw   MAX_TBLINDEX
    subwf   tableindex,w
    btfss   STATUS,C        ; if (tableindex >= 0x0A) thentableindex = 0
    goto    KeepLoop
    clrf    tableindex      ; tableindex = 0
KeepLoop:
    goto    MainLoop        ; Goto MainLoop
; Predefined value table for Automatic PWM
tablepwm1:
    addwf   PCL,f
    retlw   0x10
    retlw   0x5A
    retlw   0x9A
    retlw   0x20
    retlw   0x40
    retlw   0x8A
    retlw   0x82
    retlw   0x30
    retlw   0x58
    retlw   0xAA
tablepwm2:
    addwf   PCL,f
    retlw   0x70
    retlw   0x8A
     retlw   0x2A
    retlw   0x30
    retlw   0x1C
    retlw   0x2A
    retlw   0x4B
    retlw   0xA0
    retlw   0x18
    retlw   0x2A
;----------------- DelayMs: MillisecondDelay Subroutine ----------------------
; Paramater: WREG = delay amount in milisecond,max: 255 millisecond
DelayMs:
    movwf   Delay + 1
DelayLoop:
    call    Delay1ms
    decfsz  Delay + 1,f     ; Decrease Delay + 1, If zero skip thenext instruction
    goto    DelayLoop       ; Not zero goto DelayLoop
    return                  ; return to the caller
;----------------- Delay1ms: 1 ms DelaySubroutine ---------------------------
Delay1ms:                    ; Total Delay: 1998 x 0.5us~ 1 ms
    movlw   0x99
    movwf   Delay
DelayLoop1:
    decfsz  Delay,f         ; Decrease Delay, If zero skip thenext instruction
    goto    DelayLoop1
DelayLoop2:
    decfsz  Delay,f         ; Decrease Delay, If zero skip thenext instruction
    goto    DelayLoop2      ; Not zero goto DelayLoop2
DelayLoop3:
    decfsz  Delay,f         ; Decrease Delay, If zero skip thenext instruction
    goto    DelayLoop3      ; Not zero goto DelayLoop2
    return                  ; Returnto the caller
    end
; EOF: laserlight.asm
The following is the Laser ProjectorProject code in C Language version:
//***************************************************************************
// File Name    : laserlight.c
// Version      : 1.0
// Description  : Laser Light ShowProject
// Author       : RWB
// Target       : Microchip PIC12F683Microcontroller
// Compiler     : HI-TECH CPIC10/12/16 MCUs (Lite Mode) V9.70
// IDE          : Microchip MPLAB IDEv8.46
// Programmer   : PICKit3 (FirmwareSuite Version: 01.25.20)
// Last Updated : 03 April 2010
// ***************************************************************************
#include <pic.h>
/*  PIC Configuration Bit:
**  INTIO     - Using Internal RC NoClock
**  WDTDIS    - Wacthdog Timer Disable
**  PWRTEN    - Power Up Timer Enable
**  MCLRDIS   - Master Clear Disable
**  UNPROTECT - Code Un-Protect
**  UNPROTECT - Data EEPROM Read Un-Protect
**  BORDIS    - Borwn Out DetectDisable
**  IESODIS   - Internal ExternalSwitch Over Mode Disable
**  FCMDIS    - Monitor Clock FailSafe Disable
*/
__CONFIG(INTIO & WDTDIS & PWRTEN& MCLRDIS & UNPROTECT \
& UNPROTECT & BORDIS & IESODIS & FCMDIS);
// Using Internal Clock of 8 MHz
#define FOSC 8000000L
#define MAX_COUNT 200
#define MAX_TMR0 0xFB
#define MAX_DEBOUNCE 0x0A
#define MAX_TBLINDEX 0x0A
unsigned char pwm_count=0;
unsigned char pwm_m1=0;
unsigned char pwm_m2=0;
unsigned chartablepwm1[10]={0x10,0x5A,0x9A,0x20,0x40,0x8A,0x82,0x30,0x58,0xAA};
unsigned chartablepwm2[10]={0x70,0x8A,0x2A,0x30,0x1C,0x2A,0x4B,0xA0,0x18,0x2A};
unsigned char tableindex=0;
/* The Delay Function */
#define    delay_us(x){ unsigned char us; \
                                us = (x)/(12000000/FOSC)|1; \
                                while(--us != 0) continue; }
void delay_ms(unsigned int ms)
{
unsigned char i;
  do{
    i= 4;
   do {
     delay_us(164);
    }while(--i);
  }while(--ms);
}
static void interrupt isr(void)
{
if(T0IF) {             // TIMER0 Interrupt Flag
   pwm_count++;       // PWM CountIncrement
   if (pwm_count >= MAX_COUNT) {
     pwm_count=0;
     GPIO1=0;         // Turn off GP1
     GPIO2=0;         // Turn off GP2
    }
   if (pwm_count == pwm_m1) {
     GPIO1=1;         // Turn On GP1
   }   

   if (pwm_count == pwm_m2) {
     GPIO2=1;         // Turn On GP2
   }      

   TMR0 = MAX_TMR0;   // InitialValue for TIMER0 Interrupt
   T0IF = 0;         // Clear TIMER0 interrupt flag
  }
}
void main(void)
{
unsigned char mode,keycount;
OSCCON=0x70;         // Select 8MHz internal clock
  /*Initial Port Used */
TRISIO = 0x39;       // GP1 andGP2 Output, GP0,GP3,GP4 and GP5 as Input
CMCON0 = 0x07;       // Turn offComparator (GP0, GP1, GP2)
GPIO = 0x00;         // Turn Offall IO
  /*Init ADC Peripheral */
ANSEL = 0x79;        // Set AN0(GP0) and AN3 (GP4) as Analog Input, Internal Clock
  /*Init TIMER0: TIMER0 Period = 1/FSOC x 4 x Prescale x TMR0*/
OPTION = 0b00000000; // 1:2 Prescale
TMR0=MAX_TMR0 ;
  /*Init Variable Used */
pwm_count=0;
pwm_m1=0;
pwm_m2=0;
mode=0;
keycount=0;
tableindex=0;
  GIE=1;                // Enable Global Interrupt

for(;;) {
   // Display the LED
   if (GPIO5 == 0) {
     keycount++;
     if (keycount > MAX_DEBOUNCE) {
       keycount=0;
       mode = mode + 1;
       if (mode > 2) mode = 0;
       if (mode >= 0x01) {
         T0IE = 1;             // Enable TIMER0 Interrupt on Overflow
       } else {
         T0IE = 0;             // Disable TIMER0 Intterupt on Overflow
         pwm_count=0;
         pwm_m1=0;
         pwm_m2=0;
         GPIO1=0;             // Turn offGP1
         GPIO2=0;             // Turn offGP2
         delay_ms(500);
       }
     }
    }
   if (mode == 1) {
     /* Read the ADC here */
     ADCON0=0b00000001;       // selectleft justify result. ADC port channel AN0
     GODONE=1;                       // initiate conversion on thechannel 0
     while(GODONE) continue;  // Waitfor ldr_left conversion done
     pwm_m1=ADRESH;           // Read 8bits MSB, Ignore 2 bits LSB in ADRESL
     delay_ms(1);
     /* Read the ADC here */
     ADCON0=0b00001101;       // selectleft justify result. ADC port channel AN3
     GODONE=1;                 // initiate conversion on the channel4
     while(GODONE) continue;  // Waitfor ldr_left conversion done
     pwm_m2=ADRESH;           // Read 8bits MSB, Ignore 2 bits LSB in ADRESL   

     delay_ms(1);
    }
   if (mode == 2) {
     pwm_m1=tablepwm1[tableindex];
     delay_ms(10);
     pwm_m2=tablepwm2[tableindex];
     delay_ms(10);
     tableindex++;
     if (tableindex >= MAX_TBLINDEX)
       tableindex = 0;
    }
  }
}
/* EOF: laserlight.c */
產生PWM輸出的簡單方法是利用PIC12F683單片機的PWM內置功能,但是由于PIC12F683僅支持一個PWM輸出,因此我們需要找到一種方法來模仿固件中的這種外設行為。大多數微控制器PWM外設都使用TIMER外設來產生脈沖。在PIC12F683中,PWM發生器使用TIMER2生成PWM輸出(CCP1),如下圖所示:
當TIMER2開始計數時,TMR2寄存器(TIMER2計數器寄存器)的值會不斷與PR2和CCPR1L寄存器進行比較。當TMR2等于CCPR1L值時,CCP1輸出將被復位;而當TMR2等于PR2值時,它將設置CCP1輸出。因此,通過如上圖所示更改CCPR1L寄存器的值,我們可以更改PWM占空比(脈沖寬度)。您可以在我以前的博客上閱讀有關使用PIC單片機PWM外設的原理的更多信息。H橋Microchip PIC單片機PWM電機控制器。
使用相同的原理,我在Microchcip PIC12F683微控制器TIMER0外設的固件中制作了PWM發生器,如下圖所示:
file:///C:/Users/User1/AppData/Local/Temp/msohtmlclip1/01/clip_image022.jpg
TIMER0基本PWM發生器的基本原理是使用TIMER0溢出中斷來增加我們的PWM計數器變量pwm_count,如果該變量達到MAX_COUNT(200),則我們將復位GP1和GP2輸出引腳。如果不同,則將其與PWM占空比控制變量pwm_m1和pwm_m2進行比較,如果相等,則只需設置GP1或GP2輸出引腳即可。現在,使用該原理,我們可以輕松地基于PIC12F683單片機TIMER0外設生成高效的PWM信號。
file:///C:/Users/User1/AppData/Local/Temp/msohtmlclip1/01/clip_image024.jpg
現在看一下實現PIC12F683單片機TIMER0外設基本PWM發生器的PIC匯編代碼:
; Checkthe TIMER0 Interrupt here
     btfss  INTCON,T0IF
     goto   ExitISR         ; If (T0IF != 1)then Exit ISR
     bcf    STATUS,RP0      ; Select Registersat Bank 0
     incf   pwm_count       ; pwm_count++
     movlw  MAX_COUNT
     subwf  pwm_count,w     ; if (pwm_count< MAX_COUNT) then CheckPWM
     btfss  STATUS,C        ; else clear GP1and GP2
     goto   CheckPWM
     bcf    GPIO,GP1        ; GPIO1=0
     bcf    GPIO,GP2        ; GPIO2=0
     goto   ExitPWM
該例程首先通過檢查INTCON寄存器上的T0IF位來檢查該中斷是否由TIMER0外設產生,如果此中斷來自TIMER0,則T0IF位將被置1(邏輯“ 1 ”),然后我們繼續增加pwm_count變量,并如果達到MAX_COUNT,我們將重置GP1和GP2輸出引腳。接下來,如果pwm_count尚未達到MAX_COUNT,則將其值與pwm_m1和pwm_m2變量進行比較,如以下代碼所示:
heckPWM:
     movf   pwm_m1,w
    subwf   pwm_count,w
    btfsc   STATUS,Z        ; if (pwm_count == pwm_m1) then Set GP1
     bsf     GPIO,GP1        ; Set GP1 Bit
CheckM2:
    movf    pwm_m2,w
    subwf   pwm_count,w
    btfsc   STATUS,Z        ; if (pwm_count == pwm_m2) then Set GP2
     bsf     GPIO,GP2        ; Set GP2 bit
當pwm_count等于pwm_m1或pwm_m2時,我們分別將GP1和GP2輸出引腳設置為“邏輯1 ” 。
要計算PWM周期,首先我們必須使用以下公式計算TIMER0周期:
TIMER0 Period = 1/Fosc x 4 x Prescale x (TMR0 + 1)
在本教程中,我們使用1:2預分頻比,TMR0 =251(0xFB)和8 MHz內部振蕩器,因此TIMER0將在以下時間中斷:
TIMER0 Period = 1/8000000 x 4 x 2 x (256 – 251)= 0.000005 second
每次TIMER0中斷(TMR0溢出)時,我們都會增加pwm_count變量,直到達到MAX_COUNT(200),然后將GP1和GP2的每個輸出引腳復位。因此,大約PWM周期可以計算如下:
PWM Period = MAX_COUNT x 0.000005 seconds = 200 x0.000005 = 0.001 second
PWM Frequency = 1 / T = 1/0.001 = 1000 Hz = 1KHz
改變直流電動機的速度
該激光投影儀項目具有兩種模式,用于控制兩個直流電動機的速度,第一個模式是使用微調端口(VR1和VR2),在該模式下,我們使用PIC12F683單片機讀取由這些微調端口(分壓器電路)產生的電壓電平。數字轉換器(ADC)外圍設備,然后應用這些ADC值來更改每個直流電動機速度。第二種方法是使用存儲在查找表中的固定值,然后分配這些值以更改每個直流電動機速度。
Microchip PIC12F683單片機具有四個可用的ADC通道。在此項目中,我們使用通道0(AN0)和通道4(AN3)。通過選擇ADCON0寄存器(ADC控制寄存器)上的requireADC通道并選擇左對齊結果(ADFM = 0),我們可以讀取ADRESH寄存器中的VR1和VR2調整端口產生的電壓值,并將這些值分配給pwm_m1和pwm_m2變量,如以下PIC匯編代碼所示:
ShowMode1:                   ; Used ADC for PWM
    movlw   B'00000001'     ; Left Justify and turn on the ADCperipheral, channel 0 (AN0)
    movwf   ADCON0          ; Vreff=Vdd
     bsf     ADCON0,GO       ; Start the ADC Conversion on channel 0(AN0)
    btfss   ADCON0,GO       ; while(GO == 1)
     goto    $-1             ; Keep Loop
    call    Delay1ms
    movlw   B'00000001'     ; Left Justify and turn on the ADCperipheral, channel 0 (AN0)
    movwf   ADCON0          ; Vreff=Vdd
     bsf     ADCON0,GO       ; Start the ADC Conversion on channel 0 (AN0)
    btfss   ADCON0,GO       ; while(GO == 1)
    goto    $-1             ; Keep Loop
    movf    ADRESH,w        ; Conversion Done, Read ADRESH
    movwf   pwm_m1          ; pwm_m1 = ADRESH
    call    Delay1ms

    movlw   B'00001101'     ; Left Justify and turn on the ADCperipheral, channel 3 (AN3)
    movwf   ADCON0          ; Vreff=Vdd
     bsf     ADCON0,GO       ; Start the ADC Conversion on channel 3(AN3)
    btfss   ADCON0,GO       ; while(GO == 1)
    goto    $-1             ; Keep Test
    call    Delay1ms
    movlw   B'00001101'     ; Left Justify and turn on the ADCperipheral, channel 3 (AN3)
    movwf   ADCON0          ; Vreff=Vdd
     bsf     ADCON0,GO       ; Start the ADC Conversion on channel 3(AN3)
    btfss   ADCON0,GO       ; while(GO == 1)
    goto    $-1             ; Keep Test
    movf    ADRESH,w        ; Conversion Done, Read ADRESH
    movwf   pwm_m2          ; pwm_m2 = ADRESH
    call    Delay1ms
    goto    KeepLoop
有關使用PICADC外設的更多信息,請閱讀我以前發布的博客PIC模數轉換器C編程。
接下來是自動模式,該模式將為PIC程序閃存上的每個PWM值分配預定值。通過使用PIC匯編器“ retlw k ”(在W寄存器上返回文字值k )指令,我們可以輕松地檢索這些值。以下PIC匯編代碼顯示了我們如何執行此操作:
ShowMode2:                   ; Used Predefined Value forPWM
    movf    tableindex,w
    call    tablepwm1       ; Call tablepwm1
    movwf   pwm_m1          ; Assigned it to pwm_m1
    movlw   .30
    call    DelayMs         ; DelayMs(30)
    movf    tableindex,w
    call    tablepwm2       ; Call tablepwm2
    movwf   pwm_m2          ; Assigned it to pwm_m2
    movlw   .30
    call    DelayMs         ; DelayMs(30)

    incf    tableindex      ; tableindex++
    movlw   MAX_TBLINDEX
    subwf   tableindex,w
    btfss   STATUS,C        ; if (tableindex >= 0x0A) thentableindex = 0
    goto    KeepLoop
    clrf    tableindex      ; tableindex = 0
...
...
; Predefined value table for Automatic PWM
tablepwm1:
    addwf   PCL,f
    retlw   0x10
    retlw   0x5A
    retlw   0x9A
    retlw   0x20
     retlw   0x40
    retlw   0x8A
    retlw   0x82
    retlw   0x30
    retlw   0x58
    retlw   0xAA
tablepwm2:
    addwf   PCL,f
    retlw   0x70
    retlw   0x8A
    retlw   0x2A
    retlw   0x30
    retlw   0x1C
    retlw   0x2A
     retlw   0x4B
    retlw   0xA0
    retlw   0x18
    retlw   0x2A
此處的原理是修改PCL(程序計數器加載)寄存器。所述PCL與所述微控制器PIC12F683程序計數器至少顯著字節和在一起PCLATH寄存器形成PIC12F683微控制器13位寬程序計數器。“ goto ”命令行為可以通過操縱PCL內容來實現,例如:
movlw   0x01
    call    tablepwm2
     nop
tablepwm2:
    addwf   PCL,f
    retlw   0x70
    retlw   0x8A
    retlw   0x2A
當PIC單片機運行“ 調用tablepwm ”指令時,它將立即將程序計數器(PCL)更改為“ tablepwm2 ”標簽所指的程序地址,即“ addwfPCL,f ”指令。當PIC微控制器執行該指令時,它將W寄存器(0x01)的內容添加到PCL寄存器中,并且PIC微控制器立即跳轉到“ PCL+ 0x01 ”程序地址。接著,它會執行“ RETLW0x8A ”指令,它簡單地返回到與主叫方0x8A的值Wˉˉ寄存器。
因此,通過增加tableindex(查找表指針)變量,我們可以輕松地在pwm_m1和pwm_m2變量中的每個變量上分配預定值。
PIC組裝的基本條件
特別是對于初學者來說,理解PIC匯編指令中令人困惑的部分之一是匯編代碼中的“ 如何實現if條件 ”。在此激光投影儀項目的PIC匯編代碼中,您注意到它使用了很多“ 如果條件 ”以使其起作用。PIC匯編程序的基本“ if condition ”可以使用以下第一個模板代碼來構建:
movf  var_1,w   ; w = var_1
subwf var_2,w   ; w = var_2 - var_1
btfss STATUS,C  ; if (var_2 >= var_1)goto label_2
goto  label_1   ; else goto label_1
goto  label_2
第一個代碼(movfvar_1,w)指示PIC微控制器將var_1的內容放入W(工作)寄存器。第二個代碼(subwfvar_2,w)指示PIC微控制器用W寄存器的內容減去var_2變量的內容,并將結果放入W寄存器中,或者我們可以記為:
W = var_2-var_1
第三碼(BTFSS - b它噸 EST ˚F寄存器,小號硤如果小號等)指示PIC微控制器,如果檢查Ç在(進位)位STATUS寄存器被設置(邏輯“ 1 “),如果將它設置然后跳到一條指令(PIC單片機實際上會自動將下一條指令gotolabel_1替換為nop指令),并執行“ goto label_2 ”代碼。如果C位清零(邏輯“ 0 ”),它將執行“ goto label_1 ”代碼。
如果var_2變量的值大于或等于var_1變量,則STATUS寄存器中的C(進位)位將始終置1(邏輯“ 1 ”)。接下來,以下代碼顯示了第二個“ if condition ”模板:
movf  var_1,w   ; w = var_1
subwf var_2,w   ; w = var_2 - var_1
btfss STATUS,Z  ; if (var_2 == var_1)goto label_2
goto  label_1   ; else goto label_1
goto  label_2
這一次,我們將研究Ž(零)在比特STATUS寄存器,該Ž(零)位將總是設置(邏輯“ 1 “)時,VAR_2值等于VAR_1值。最后,以下代碼顯示了第三個“ ifcondition ”模板:
movlw 0x08      ; w = 0x08
subwf var_1,w   ; w = var_1 - 0x08
btfss STATUS,C  ; if (var_1 >= 0x08)goto label_2
goto  label_1   ; else goto label_1
goto  label_2
第三個模板只是第一個模板的變體,這次我們將字面值0x08加載到W寄存器中,并將其與var_1變量進行比較。通過僅使用這三個“ ifcondition ”模板,您可以輕松地在代碼中實現多種類型的“ ifcondition ”。關鍵要理解和執行PIC匯編“ 如果條件 ”在你的代碼指令成功地,始終如一地使用這些模板,一旦你了解比你能修改或用結合起來BTFSC(b它牛逼 EST ˚F寄存器,小號基普如果Çlear)(bit test f register, skipif clear)指令或影響STATUS寄存器中C和Z位的任何PIC匯編程序指令,使您的匯編代碼更高效。
為了使PIC匯編代碼更易于理解,在此激光投影儀教程中,我在代碼中添加了很多注釋,您還可以將其與為該項目提供的等效C語言代碼進行比較。C語言代碼使用與PIC匯編代碼中相同的變量名,以便于比較。
PIC匯編程序代碼內部
激光投影儀項目使用PIC12F683單片機TIMER0和ADC外設來控制每個直流電動機的速度。以下說明用于初始化PIC12F683外設
Main:
     bsf     STATUS,RP0      ; Select Registers at Bank 1
    movlw   0x70
    movwf   OSCCON          ; Set the internal clock speed to 8MHz
    movlw   0x39            ; GP1 and GP2 Output, GP0,GP3,GP4and GP5 as Input
    movwf   TRISIO          ; TRISIO = 0x39        

     bcf     STATUS,RP0      ; Select Registers at Bank 0
    movlw   0x07
    movwf   CMCON0          ; Turn off Comparator (GP0, GP1, GP2)
    clrf    GPIO

; Now we Set the ADC Peripheral
     bsf     STATUS,RP0      ; Select Registers at Bank 1
    movlw   0x79           ; Set AN0 (GP0) and AN3 (GP4) as Analog Input
    movwf   ANSEL           ; Using the Internal Clock(FRC)  

; Now we set the TIMER0 Peripheral
; TIMER0 Period = 1/FSOC x 4 x Prescale x TMR0
    movlw   0x00            ; Use TIMER0 Prescaler 1:2,Internal Clock
    movwf   OPTION_REG      ; OPTION_REG = 0x00
     bcf     STATUS,RP0      ; Select Registers at Bank 0
    movlw   MAX_TMR0
    movwf   TMR0            ; TMR0=MAX_TMR0     

; Initial the variables used
    clrf    mode            ; Default mode = 0, Light Show Off
    clrf    pwm_count       ; pwm_count = 0
    clrf    pwm_m1          ; pwm_m1 = 0
    clrf    pwm_m2          ; pwm_m2 = 0
    clrf    keycount        ; keycount = 0
    clrf    tableindex      ; tableindex = 0
; Activate the Interrupt
     bsf     INTCON,GIE      ; Enable Global Interrupt

第一條指令是將OSCCON(振蕩器控制)寄存器設置為使用8MHz內部時鐘,然后我們將TRISIO(三態I / O控制器緩沖器)寄存器設置為輸入和輸出端口,并關閉CMCON0上的比較器外設(比較器控制)寄存器。復位GPIO(通用I / O)寄存器后,我們繼續設置ADC外設的ANSEL(模擬選擇)寄存器和TIMER0外設的OPTION_REG,并通過清除它們來初始化程序中使用的所有變量。
在進入無限循環之前,我們立即激活INTCON(中斷控制)寄存器中的GIE(全局中斷使能)位,以便當TMR0TIMER0計數器)寄存器溢出(大于255)時發生TIMER0中斷。
在無限循環內(MainLoop標簽),我們不斷檢查模式變量。該模式值被用于確定所述程序的行為。當模式值為0,程序將簡單地連續循環;當模式值為1,程序將使用ADC值來控制每個直流電動機速度;而當模式值為2,程序將使用外觀-上表來控制PWM信號(自動模式)。
PIC匯編代碼和C代碼比較
由于在此項目中,我將PIC匯編語言和C語言用于固件;因此,比較兩個十六進制程序的大小會很有趣。以下是由MicrochipPIC匯編器和HI-TECH C PRO(精簡模式)編譯器生成的HEX代碼。
HI-TECH C PRO編譯器生成的HEX代碼在精簡模式356字(623字節),但是,如果在PRO模式編譯C代碼,則其大小將減小40%或約為214字( 374.5字節),另一方面,Microchip宏匯編器為HEX代碼生成180個字(315字節)。現在您可以看到,如果我們使用專業的C語言編譯器,它將生成非常小的HEX代碼,幾乎與匯編語言生成的HEX代碼相等。
下載十六進制代碼
在編譯并模擬了代碼之后,是時候使用MicrochipPICKit3編程器下載代碼了,將PICKit3ICSP(微電路在線串行編程)端口連接到PIC12F683單片機引腳,然后從Programmer菜單中選擇Programmer-> PicKit3,然后選擇Programmer ->程序菜單,將您的十六進制代碼下載到PIC12F683單片機閃存中。


原文鏈接:
游客,本帖隱藏的內容需要積分高于 1 才可瀏覽,您當前積分為 0

laserlight_13.jpg (115.97 KB, 下載次數: 160)

laserlight014

laserlight014

laserlight_12.jpg (134.31 KB, 下載次數: 160)

laserlight012

laserlight012

laserlight_11.jpg (93.46 KB, 下載次數: 158)

laserlight011

laserlight011

laserlight_10.jpg (76.29 KB, 下載次數: 151)

laserlight010

laserlight010

laserlight_09.jpg (75.97 KB, 下載次數: 140)

laserlight09

laserlight09

laserlight_04.jpg (51.49 KB, 下載次數: 159)

laserlight04

laserlight04

laserlight_01.jpg (71.47 KB, 下載次數: 156)

laserlight01

laserlight01

laserlight_02.jpg (38.32 KB, 下載次數: 153)

laserlight02

laserlight02

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏3 分享淘帖 頂1 踩
回復

使用道具 舉報

沙發
ID:631408 發表于 2019-12-8 19:02 | 只看該作者
先收藏為敬,謝謝樓主
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 女女爱爱视频 | 国产美女精品 | 欧美日韩精品专区 | 国产欧美精品一区二区三区 | 三级免费 | 国产一级免费在线观看 | 欧美xxxx性 | 欧美三级久久久 | 国产精品一区二 | 国产亚洲精品久久午夜玫瑰园 | 国产激情在线看 | 韩国主播午夜大尺度福利 | 伊人导航 | 国产精品成人在线播放 | 免费的网站www | 久久精品网 | 国产9999精品 | 韩国精品在线观看 | 99国产精品久久久久久久 | 最新中文字幕一区 | 99精品久久久 | 天堂中文字幕av | 国产成人a亚洲精品 | 久久精品日产第一区二区三区 | 成人在线观看免费 | 黄毛片| 国产美女特级嫩嫩嫩bbb片 | 精产国产伦理一二三区 | 伊色综合久久之综合久久 | 精品久久久久久红码专区 | 亚洲一一在线 | 91麻豆产精品久久久久久 | 91视频观看| 天堂在线免费视频 | 成人影音 | 欧美三级在线 | 午夜成人免费视频 | 国产精品久久久久一区二区三区 | 日韩欧美黄色 | 精品视频一区二区三区在线观看 | 精品91av |