半年ほど前にプログラムの構成見直しに着手したものの、具体的な進捗がなかったが年末年始休みを使って、勉強しながら形にすることができた。 難しい処理については、新たに関数をつくって functions.c に記述して見えないようにした。生徒が変更すべきものはmain.cだが以下の通り
/* File: LiLaC-v2.4 main.c * Created on 2023/01/04 */ #include "<"xc.h">" #include "<"stdio.h">" #include "LiLaC-v24functions.h" int main(void) { setting(); //コンピュータ(12F683)の初期設定 /*しきい値(Threshold)の設定 INPUT1のしきい値をthre1 INPUT2のしきい値をthre2としてここに設定*/ thre1=512; /* INPUT1 0から1024の間の値、中心値は512 これでスイッチのオン・オフを設定★こちらピンソケット★*/ thre2=512; /* INPUT2 0から1024の間の値、中心値は512 これでスイッチのオン・オフを設定★こちらボリューム付き★*/ start_select();// 論理選択スイッチをandスタート、1秒以内にorにすると計測モードへ while(1){//ここからプログラム本体(変更堪能なところ) logic_set(); //論理選択スイッチの値を読み込み get_sensor_data(); //センサーの値を読み込み /*論理選択スイッチの値によって分岐する andは1 orは2 */ switch(SW_f){ case 1: /*AND回路 */ if (in1_f & in2_f){ // AND演算が成立した場合 OUTPUT1 = ON; // OUTPUT2 = ON; // set_angle(90); // サーボモータ角度設定 spend_time(5); // ONを継続する時間(秒) } else{ // AND演算が成立しなかった場合 OUTPUT1 = OFF; OUTPUT2 = OFF; set_angle(0); // サーボモータ角度設定 } break; //AND回路分終了 case 2: /*OR回路 */ if (in1_f | in2_f){ // OR演算が成立した場合 OUTPUT1 = ON; OUTPUT2 = OFF; set_angle(180); // サーボモータ角度設定 spend_time(2); // ONを継続する時間(秒) } else{ // OR演算が成立しなかった場合 OUTPUT1 = OFF; OUTPUT2 = OFF; set_angle(45); // サーボモータ角度設定 } break; //OR回路分終了 } } }
となるが、コメントがあると長くなって余計にわかりにくくなるので整理して画像のコメントを付け足すと となる。これを個々に保存して開発環境の入っているPCにコピペしてコンパイル&書き込みというのが現実的だろうか。ちなみに、今回作って変更しない&見えないようにしておく関数の束は functions.c として保存した。中身は以下の通りとなる。
/* File: LiLaC-v2.4 functions.c 機能用関数 * Created on 2023/01/04 */ #include "LiLaC-v24functions.h" #include "<"xc.h">" #include "<"stdio.h">" void setting(void){/*★PIC(12F683)の初期セッティング★*/ OSCCON = 0b01000000; //内部クロックの設定 1MHzに設定 /*ポートの入出力の設定 4と5を出力 2と3を機能切り替えスイッチ 0と1をアナログ入力 データシート36pより 1が入力、0が出力*/ TRISIO =0b00001011; ANSEL = 0b00000011; //AD変換クロック>2Tosc アナログ入力ピンの設定 0と1をアナログ入力 CMCON0 = 0b00000111; //コンパレータはオフ T2CON = 0b00000110; //タイマー2の動作設定ポストスケーラ回数:毎回1 プリスケーラ分周比1:16 CCP1CON = 0b00001100; //PWMモードの指定 PWMオン /*サーボモータ パルス周期 T=15ms T=(PR2設定値+1)×プリスケーラ分周比×クロック周期×4×ポストスケーラ回数 上記変形により PR2=233 角度(変数:angle)を 0?180°とすると angle×233÷180 によってホーンの位置が決定する。*/ PR2 = 255; CCPR1L = 25; } void start_select(void){/* ★起動時に選択して計測モードへ ★ */ /*論理回路選択スイッチの値(SW_f)をセットする andは1 orは2 */ /*プルアップしているため このスイッチは オンが0 オフが1 */ if (SW1 == 0){ __delay_ms(1000); if (SW1 == 1){/*ここから計測モード開始*/ while(1){ logicset(); get_sensor_data(); /*論理選択スイッチの値によって分岐する 論理選択スイッチをここでは、AD変換ポートの 1と2の切り替えに使っている。 sw1→ポート1 sw2→ポート2 */ switch(SW_f){ case 1: /*インプット1の値表示 sw1>ON */ angle = adc1 * 0.18; /* 180 ÷ 1024 =0.1757 */ set_angle(angle); OUTPUT1 = ON; __delay_ms(200);//待ち時間0.2秒 break; case 2: /*インプット2の値表示 sw1>OFF */ angle = adc2 * 0.18; /* 180 ÷ 1024 =0.1757 */ set_angle(angle); OUTPUT1 = 0; __delay_ms(200);//待ち時間0.2秒 break; } } } } } void logicset(void){/*★論理回路選択スイッチの位置判定★*/ /*論理回路選択スイッチの値(SW_f)をセットする andは1 orは2 */ /*プルアップしているため このスイッチは オンが0 オフが1 */ if (SW1 == 0){ SW_f = 1; } if (SW1 == 1){ SW_f = 2; } } void get_sensor_data(void){/*★2つのセンサー値を取得★*/ /*INPUT1のデータを読み込んでadc1に入力*/ /*INPUT1 ADC初期設定*/ ADCON0 = 0b10000001;//右詰め|基準電圧は電源Vdd)|空白|空白||AN0|ADC終了|ADC有効 __delay_us(4);//ADC充電時間 GO = 1;//ADC変換開始 while(GO);//ADC変換終了までループ待機 adc1 = ADRESH*256 + ADRESL;//adc1にADC 0>1024段階の値を入れる /*INPUT2のデータを読み込んでadc2に入力*/ /*INPUT2 ADC初期設定*/ ADCON0 = 0b10000101;//右詰め|基準電圧は電源Vdd)|空白|空白||AN1|ADC終了|ADC有効 __delay_us(4);//ADC充電時間 GO = 1;//ADC変換開始 while(GO);//ADC変換終了までループ待機 adc2 = ADRESH*256 + ADRESL;//adc2にADC 0>1024段階の値を入れる /*AD変換した結果をデジタルのオンオフデータに*/ if(adc1 > thre1){ /*INPUT1の値*/ in1_f = 1; /*しきい値より大きければ 1 */ } else{ in1_f = 0; /*しきい値より小さければ 0 */ } if(adc2 > thre2){ /*INPUT2の値*/ in2_f = 1; /*しきい値より大きければ 1 */ } else{ in2_f = 0; /*しきい値より小さければ 0 */ } } void spend_time(tim_sec){/*★時間を経過させる★*/ tim_cnt = 0; /*onになっている指定時間を待つ*/ while(tim_sec > tim_cnt){ __delay_ms(1000); tim_cnt++; } } void set_angle(angle){ /*★サーボモータの位置を動かす★*/ r_start = 6; r_end = 38; angle_pulse = (180 - angle) * (r_end - r_start) / 180 + r_start; CCPR1L = angle_pulse; }
もう一つ必要なのは、初期設定のヘッダーファイル
/* * File: LiLaC-v24functions.h * Author: dai_a * * Created on 2023/01/04 */ // PIC12F683 Configuration Bit Settings // 'C' source line config statements // CONFIG #pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/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 // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD) #pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled) #pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) #pragma config BOREN = OFF // Brown Out Detect (BOR disabled) #pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled) // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. #define _XTAL_FREQ 1000000 /*ピンの定義をしておく*/ #define OUTPUT1 GP5 #define OUTPUT2 GP4 #define SW1 GP3 #define MOTOR GP2 #define INPUT1 AN0 #define INPUT2 AN1 /*状態の定義をしておく*/ #define ON 1 #define OFF 0 /*グローバル変数の宣言*/ short int SW_f; //切り替えスイッチの値はSW_fとして 1=and 2=or に割り当てる short int adc1,adc2; //入力ポートの値はadc1 adc2 として 10bitの値を用いる short int in1_f,in2_f; //入力結果(オンかオフか)は 2つのポートを in1_f in2_f として どちらも0か1が入る short int tim_sec,tim_cnt; //ウエイトに使うカウンタ変数 short int thre1,thre2; //しきい値(Threshold) INPUT1のしきい値をthre1 INPUT2のしきい値をthre2 /*グローバル変数(サーボモータアングル関係)の選言*/ int angle; //指針の角度 int angle_pulse; //指針の角度をサーボモータのステップにしたもの int r_start; //指針の始まり 0° int r_end; //指針の最終 180° /*作った関数の一覧(宣言)*/ void start_select(); void setting(); void logicset(); void get_sensor_data(); void spend_time(); void set_angle();
今回でそこそこc言語によるプログラム開発のスキルが身についた感じがする50(後半)の手習いと言ったところか。