■自作ミニ四駆ラップタイマーPICプログラムソースリスト
/* * PICのプログラムミングやプログラムの書き込みは * 他の方のブログやメーカーのホームページを参考にしてください。 * 私はこれを参考書に学習しました。 * 「PICATOWER C言語プログラミングマニュアル」(株式会社イーケイジャパン) * PICマイコンとC言語のマニュアルとしてコンパクトにまとまっています。 * 株式会社イーケイジャパンに感謝です。 *//* * File: Laptimer_3.c * Author: WAT * * Created on 2017/05/10, 14:50 */// PIC16F648A による ミニ四駆のラップタイマー ハードウェアー仕様/********************************************** RA7->入力:OSC2 EXTERNAL XTAL:20MHz * RA6->出力:OSC1* RA5->入力:push_sw PUSH=Low* RA4->入力:sensor object detection=Low* RA3->出力:ndigit[4] 10^4* RA2->出力:ndigit[3] 10^3* RA1->出力:ndigit[1] 10^1* RA0->出力:ndigit[2] 10^2* RA0~RA3->High:ndigit[0] 10^0**************************************************//********************************************** RB7->出力:b a* RB6->出力:a ---* RB5->出力:g f| g |b* RB4->出力:f ---* RB3->出力:e e| |c* RB2->出力:c --- ・DP* RB1->出力:DP d* RB0->出力:d**************************************************/#include <xc.h>// PIC16F648A Configuration Bit Settings// 'C' source line config statements// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.// CONFIG#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)#pragma config MCLRE = OFF // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)#define _XTAL_FREQ 20000000 // 20MHz#define _1keta 0b00001111#define _2keta 0b00001101#define _3keta 0b00001110#define _4keta 0b00001011#define _5keta 0b00000111#define KETA PORTA#define SEGMENT PORTB#define DOT RB1#define sensor RA4#define push_sw RA5#define DP 0b00000010 // 小数点#define DED_TIME 1000 // 車両通過時間 センサー不感時間#define DETECT 0 // Low#define PUSH 0 // Low#define clear 0 // ゼロ#define enable 1 // 1#define disable 0 // 0#define turn_on 1 // ON#define turn_off 0 // OFFunsigned char digit[5]={0,1,2,3,4}; //カウント値を各桁に分解して配列に格納unsigned char disp_flag,digit_count; //表示タイミング,桁位置unsigned int Laptime,count_delay=clear; //ラップタイム,デッドタイム/******************************************************************** 10進数をセグメントデータに変換するセグメントデータを定義*******************************************************************/const unsigned char _7seg_pattern[16] = {// bagfecDPd 0b11011101, // '0' 0b10000100, // '1' 0b11101001, // '2' 0b11100101, // '3' 0b10110100, // '4' 0b01110101, // '5' 0b01111101, // '6' 0b11000100, // '7' 0b11111101, // '8' 0b11110101, // '9' 0b11111100, // 'A' 0b00111101, // 'b' 0b01011001, // 'C' 0b10101101, // 'd' 0b01111001, // 'E' 0b01111000 // 'F' };void _5to1keta( ); // プロトタイプ宣言void num2seg( ); // プロトタイプ宣言void main(void) { // 割り込み設定 OPTION_REG = 0b10000100; // 内部クロック20MHz÷4=5MHz /***************************************** *b7 WPUEN--> 1:pullup disable * 0:pullup enable *b6 INTEDG 1:rising edge * --> 0:falling edge *b5:TMROCS 1:TOCKLpin * --> 0:Internal clock *b4 1:High to low * --> 0:Low to high *b3 PSA 1:PS not assigned * --> 0:PS assin Timer0 *b2-0 PS 0:1/2 * 1:1/4 * 2:1/8 * 3:1/16 * --> 4:1/32 * 5:1/64 * 6:1/128 * 7:1/256******************************************/ TMR0 = clear; // タイマー0初期化 TMR0IF = clear; // タイマー0割り込みフラグクリア TMR0IE = enable; // タイマー0割り込み許可 GIE = enable; // 全割り込み許可 TRISA = 0b10110000; // ポートRA0-3出力に設定,ポートRA4-5入力に設定 TRISB = 0b00000000; // ポートRB0-7出力に設定 while (1) { if (disp_flag ){ // ダイナミック表示タイミング? disp_flag = clear; digit_count++; // 桁カウンタインクリメント if (digit_count > 5) // 桁カウンタオーバーフロー? digit_count = clear; // 桁カウンタリセット _5to1keta(Laptime); // 10進5桁の数を1桁の配列に格納 num2seg(digit_count); // 7segデータを出力 } } return;} /************************************************* 10進5桁のラップタイムを1桁×5の配列に格納する digit[4]->10000の桁、digit[3]->1000の桁、digit[2]->100の桁、 digit[1]->10の桁、digit[0]->1の桁*************************************************/ void _5to1keta( Laptime ){ // 数値データを各桁にする関数 unsigned char temp; // ローカル変数を定義 unsigned int n; int i; // for(i=0;i<5;i++){ // digit[i] = 0; // 配列クリア// } n = Laptime; // ラップタイムを取得 for(i=0;i<5;i++){ temp = n % 10; // 下位の桁から数字1桁を抽出 digit[i] = temp; // 配列へ格納 n /= 10; // 下位桁を削除 }}/************************************************* 10進1桁配列の数値を7セグデータに変換して出力する*************************************************/ void num2seg( digit_count ){ // 数値7segデータ変換 SEGMENT = turn_off; // 7セグ 非表示 switch( digit_count ){ case 0: // 1桁目 表示 KETA = _1keta; // 1桁目選択 SEGMENT = _7seg_pattern[digit[0]]; // 7セグパターン表示 if (sensor == DETECT) // センサー状態? DOT = turn_on ; // センサー検出表示 break; case 1: // 2桁目 表示 KETA = _2keta; // 2桁目選択 SEGMENT = _7seg_pattern[digit[1]]; // 7 セグパターン表示 break; case 2: // 3桁目 表示 KETA = _3keta; // 3桁目選択 SEGMENT = _7seg_pattern[digit[2]]; // 7セグパターン表示 break; case 3: // 4桁目 表示 KETA = _4keta; // 4桁目選択 SEGMENT = _7seg_pattern[digit[3]]; // 7セグパターン表示 DOT = turn_on; // 4桁目小数点表示 break; case 4: // 5桁目 表示 KETA = _5keta; // 5桁目選択 if (digit[4] !=0 ) // 5桁目のみゼロサプレス SEGMENT = _7seg_pattern[digit[4]]; // 7セグパターン表示 }}/*************************************************/ タイマー0割り込み 1ms/ ラップタイムのカウントと7セグLED表示更新周期4ms作成*************************************************/ // 割り込み処理ルーチンvoid interrupt timer0_int(void) { unsigned char count_4ms; unsigned int counter,sense_in; GIE = disable; // 割り込みを不許可とする TMR0IF = clear; // タイマー0オーバーフローフラグをクリアする/*************************************************/ センサーを読んでラップタイムを更新する*************************************************/ //CPUクロック 20MHz, 1/4 プリスケーラー, 1/32 5000KHz÷32= 156.25KHz//256-100=156 156.25÷156=1.0016KHz(0.9984ms)(-0.16%) TMR0= 100; // タイマー0 に100をセットし、再スタート counter++; // ラップタイムカウンタを+1 count_4ms++; // 4msカウンタを+1 if (count_4ms > 3){ // 表示タイミング? disp_flag = enable; // 表示タイミングフラグをセット count_4ms = clear; // 4msカウンタをクリア } if (count_delay > 0) count_delay-- ; // ディレイタイマーゼロまでカウントダウン if ( ( sensor == DETECT )||( push_sw == PUSH )){ //センサー検出? または SW押下? sense_in++; // センサー通過時間カウント if (( sense_in == 2 ) && ( count_delay == 0 )){ // 2ms?(ノイズ除去)かつ 一定時間経過? Laptime = counter; // 現在のカウンタ値をラップタイムとし counter = clear; // ラップタイムカウンタをクリア count_delay = DED_TIME; // 1度検出したら車両通過を待つ } } else{ // センサー非検出 sense_in = clear; // sensorがHighならsense_inリセット } GIE = enable; // 割り込みを許可する return;}