最近、ぼちぼちPICやってます。
最初は全部レジスタ直打ちで全部の機能を使おうとしていたのですが、あまりにも非効率なので、一旦諦めてMicrochipがMPLABXに付属させているMCCというコードジェネレータを使うことにしました。コードジェネレータと言っても、GUIで設定するとハードウェアを使う機能の関数が用意されるだけで、その関数をどう使うかは自分次第です。
なれるとなかなか便利な代物で、例えばPWM1_DutyCycleSet(100);とか書くだけでDuty比がセットできるようになったりするので、高度な制御をするときは必須かなと思いました。
今回は高周波PWM制御で鉄道模型を精密制御するものを作りました。被制御側(ハード、PIC)はこんな感じで良さそうですが、Pythonとかで制御するソフトウェアが未完成なので、まだシリアルから手動で叩く必要があります。
今回は書籍「C言語によるPICプログラミング大全」を参考にしました。基本から書いてありますが、いきなりレベルが吹っ飛びすぎて、下地がないと厳しいかもしれないです。MPLAB XとMCCの使い方については参考となる日本語資料が少ないので助かりました。
ハードについては、今回、唐突にPICがリセットされる問題が発生して解決に時間を要しました。結局、電源ラインにセラミックコンデンサを入れ忘れておりず、ノイズでリセットされていたことがわかりました。基本的なことなので、書籍などを参考にしなかったのが原因かもしれないです。まあ、気づけてよかったです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "mcc_generated_files/mcc.h" | |
#include <stdio.h> | |
void move(unsigned char direction) | |
{ | |
if (direction == 1) { | |
PWM1_DutyCycleSet(639); | |
PWM1_LoadBufferSet(); | |
} else { | |
PWM2_DutyCycleSet(639); | |
PWM2_LoadBufferSet(); | |
} | |
__delay_ms(10); | |
} | |
void main(void) | |
{ | |
// initialize the device | |
SYSTEM_Initialize(); | |
// Enable the Global Interrupts | |
INTERRUPT_GlobalInterruptEnable(); | |
// Enable the Peripheral Interrupts | |
INTERRUPT_PeripheralInterruptEnable(); | |
unsigned int level = 0; | |
unsigned int new_level = 0; | |
unsigned char direction = 1; | |
unsigned char got_char; | |
dir2_SetLow(); | |
PWM1_Start(); | |
PWM1_DutyCycleSet(0); | |
PWM1_LoadBufferSet(); | |
printf("init\n\r"); | |
while (1) | |
{ | |
got_char = EUSART_Read(); | |
// if (PIR1bits.RCIF) { | |
// got_char = RCREGbits.RCREG; | |
// } | |
if (got_char < '!'){ | |
if (direction == 1) { | |
if (level) { | |
PWM1_DutyCycleSet(level * 3 / 4); | |
PWM1_LoadBufferSet(); | |
__delay_ms(500); | |
} | |
PWM1_DutyCycleSet(0); | |
PWM1_LoadBufferSet(); | |
PWM1_Stop(); | |
__delay_ms(500); | |
dir2_SetHigh(); | |
__delay_ms(200); | |
PWM2_Start(); | |
PWM2_DutyCycleSet(level); | |
PWM2_LoadBufferSet(); | |
printf("houten to 2\n\r"); | |
direction = 2; | |
if (level) { | |
move(direction); | |
} | |
} else { | |
if (level) { | |
PWM2_DutyCycleSet(level * 3 / 4); | |
PWM2_LoadBufferSet(); | |
__delay_ms(500); | |
} | |
__delay_ms(500); | |
PWM2_DutyCycleSet(0); | |
PWM2_LoadBufferSet(); | |
PWM2_Stop(); | |
dir2_SetLow(); | |
__delay_ms(200); | |
PWM1_Start(); | |
PWM1_DutyCycleSet(level); | |
PWM1_LoadBufferSet(); | |
printf("houten to 1\n\r"); | |
direction = 1; | |
if (level) { | |
move(direction); | |
} | |
} | |
} else if (got_char < '~') { | |
new_level = (got_char – '!') * 5; | |
printf("%d", new_level); | |
} | |
if (new_level > level) { | |
move(direction); | |
} | |
//ADC1_GetConversion(channel_AN11) | |
level = new_level; | |
if (direction == 1) { | |
PWM1_DutyCycleSet(level); | |
PWM1_LoadBufferSet(); | |
} else { | |
PWM2_DutyCycleSet(level); | |
PWM2_LoadBufferSet(); | |
} | |
__delay_ms(50); | |
} | |
} |