PWM for PIC12F629
ページを編集するにはログインが必要です。
CCP回路が実装されていないPIC12F629でPWMを行う。
PIC16F877AにはCCP(キャプチャ・コンペア)回路が実装されており、PWM制御を比較的簡単に行うことが出来る。多機能だが、40Pinパッケージでサイズが大きく、部品単価も高い(@500-程度)。8Pinパッケージで、低価格(@120-程度)のPIC12F629でPWMによるLEDやMotorの制御が行いたい。
今回はPICアセンブラはかったるいので、B Knudsen Data(Norway)のCC5XというCコンパイラ仕様で、ちゃちゃっと書いてみた。割り込みハンドラで、約35uS毎のパルス制御、約500mS毎の時間制御、sleepからのwakeupを行っている。パルスパターンは const char pt[] に宣言したものを用いる。部品数低減の為clockは内部発振回路。遅いので、motorなどを回すと微妙なスイッチング音が確認出来る。電車でも鳴ってるやつがあるんだから、まっ、いいだろう。
以下、Cソースをそのまま載せる。各自解読するように。コメントに嘘が書いてある場合があるので注意のこと。
改めてソースを眺めて今思ったけど、割り込みハンドラの中身はきちんと else if にするか switch/case文の方がいいかもね。
PIC16F877AのPWMについては、 「作りながら学ぶPICマイコン入門」 神崎康宏 著 CQ出版株式会社 ISBN4-7898-3736-X 2005年5月1日 初版発行 ¥2,730- を、各自購入して研究しなさい。(神崎氏及びCQ出版とは利害関係は一切ない)
/* * pwm_test.c for PIC12F629 * Ver1.00 2007/05/05 Written by H.Nitobe * (C)Copyright 2007 Hiroaki Nitobe All rights reserved. */ //#pragma optimize = 0 #include <INT16CXX.h> //#include ../"12f629.h" /* +--\_/--+ (5V)VDD --|1 8|-- VSS(0V) GP5 XX|2 7|-> GP0(ICSPDAT) --> to Motor GP4 XX|3 6|XX GP1(ICSPCLK) [VPP] X>|4 5|<- GP2/INT -------< from Switch *-------+ */ // Chip Settings #define CP_off |= 0x2180 // Bandgap value + CPD(disable) + CP(disable) #define MCLR_off &= ~0x80 #pragma config BODEN = off, MCLR_off, PWRTE = on, WDTE = off, FOSC = 4, CP_off // Definitions #define true !0 #define false 0 #define ON 1 #define OFF 0 // Function Prototypes interrupt int_server( void); void main(void); void wait(char count); // Global Variables char tick; char pattern; const char pt[] = { 0b.0000.0000, // 0% 0b.0000.0001, // 12.5% 0b.0001.0001, // 25% 0b.0001.0101, // 37.5% 0b.0101.0101, // 50% 0b.0101.0111, // 62.6% 0b.0111.0111, // 75% 0b.0111.1111, // 87.5% 0b.1111.1111}; // 100% // Interrupt Server #pragma origin 4 interrupt int_server( void) { int_save_registers RP0 = 0; // page#0 if(T0IF){ T0IF = OFF; // Clear T0 Flag TMR0 = 220; // 255 - 220 = 35Cycles = 35uS W = rr(pattern); // Rotate Right F through C to W pattern = rr(pattern); // Rotate Right F through C to F if(pattern.0){ // OUTPUT Bit0 of pattern GPIO0 = ON; // Motor ON } else { GPIO0 = OFF; // Motor OFF } } if(TMR1IF){ // 500mS Interrupt TMR1IF = OFF; // Clear T1 Flag TMR1L = 221; // (65535-3037)*8 = 499984uS TMR1H = 11; // 3037 = 11*256+221 tick += 1; // Incriment tick } if(INTF){ // Wakeup from sleep INTF = OFF; // Clear Int Flag (SW ON) } int_restore_registers } // Main Routine void main(void) { char i; // Initialize RP0 = 1; // page#1 #asm DW /*CALL*/ 0x2000 + 0x3ff #endasm OSCCAL = W; // 90h: Set OSCCAL OPTION = 0b.0000.1000; // 81h: TMR0 1:2 prescaler divide by 2 RP0 = 0; // page#0 INTCON = 0b.0000.0000; // 0bh: CMCON = 0b.0000.0111; // 19h: Not Use COMP GPIO = 0b.0000.0000; // 05h: T1CON = 0b.0011.0000; // 10h: 1/8 Prescale TMR0 = 220; // 01h: TMR1L = 221; // 0eh: TMR1H = 11; // 0fh: RP0 = 1; // page#1 TRISIO = 0b.0000.0100; // 85h: WPU = 0b.0000.0100; // 95h: // Main Routine while (1) { RP0 = 0; // page#0 INTCON = 0b.1001.0000; // 0bh: GIE | INTE T1CON = 0b.0011.0000; // 10h: TMR1ON_OFF RP0 = 1; // page#1 PIE1 = 0b.0000.0000; // 8ch: TMR1IE_OFF nop(); // for BreakePoint of Debugger sleep(); // Sleeps until Switch-ON nop(); // for BreakePoint of Debugger RP0 = 0; // page#0 INTCON = 0b.1110.0000; // 0bh: GIE | PEIE | T0IE T1CON = 0b.0011.0001; // 10h: TMR1ON_ON RP0 = 1; // page#1 PIE1 = 0b.0000.0001; // 8ch: TMR1IE_ON pattern = pt[3]; // Start 0.5s wait(1); pattern = pt[2]; // Pattern(2) 2.5s wait(5); for(i = 3; i < 8; i++) { pattern = pt[i]; // Pattern(3-7) 5s wait(2); } pattern = pt[8]; // Pattern(8) 3s wait(6); for(i = 7; i > 2; --i) { pattern = pt[i]; // Pattern(7-3) 5s wait(2); } pattern = pt[2]; // Pattern(2) 3s wait(6); for(i = 3; i < 8; i++) { pattern = pt[i]; // Pattern(3-7) 5s wait(2); } pattern = pt[8]; // Pattern(8) 3s wait(6); for(i = 7; i > 2; --i) { pattern = pt[i]; // Pattern(7-3) 5s wait(2); } pattern = pt[2]; // Pattern(2) 3s wait(6); } } // Subroutine of Time Count void wait(char count) { tick = 0; // tick = 500mS while(tick < count); return; }
Keyword(s):[PIC] [PIC12F629]
References: