#include <pic.h>
#include "delay.h"
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
//
// 別途必要な関数ファイル:
// delay.c (注意:使用するクロック周波数を設定すること PICC-LITE用にチューン済
// pic.h
// delay.h
//
// [I/O情報] ピン番号 (先頭ビット DO:出力 DI:Digital入力 AI:Analog入力 .K:外部正論理 .N:外部不論理)
// 19.RA0:DO.K ,RA0 /ICSPDAT専用 (通常時出力)
// 18.RA1:DO.K ,RA1 /ICSPCLK専用 (通常時出力)
// 17.RA2:DO.K ,RA2 /リレー出力R1
// 4.RA3:DI.K ,RA3 /ICSPMCLR専用 VPPtarget (通常時入力専用 //未使用)
// 3.RA4:AI.K ,AN3 /トリマVol (スイッチの照光ランプから変更)
// 2.RA5:DI.K ,RA5 /押しボタンスイッチ(自動-手動)
// 13.RB4:DI.K ,RB4 /DIP-SW3入力
// 12.RB5:DI.K ,RB5 /DIP-SW2入力
// 11.RB6:DI.K ,RB6 /DIP-SW1入力
// 10.RB7:DO.K ,RB7 /未接続 (通常時出力)
// 16.RC0:DO.K ,RC0 /リレー出力R2
// 15.RC1:DO.K ,RC1 /ブザー出力
// 14.RC2:DI.K ,RC2 /DIP-SW4入力
// 7.RC3:AI.K ,AN7 /ポテンショメータ左入力
// 6.RC4:DO.K ,RC4 /スイッチ照光ランプ
// 5.RC5:DO.K ,RC5 /未接続 (通常時出力)
// 8.RC6:AI.K ,AN8 /ポテンショメータ右入力
// 9.RC7:AI.K ,AN9 /操作ボリューム入力
//
// [システム情報] //別プログラムのコピペにつき未編集
// 動作クロック :たぶん4MHz
// timer0 :未使用
// timer1 :未使用
// コンパレータ :未使用
// A/Dコン :未使用
// EEPROM :未使用
// ウォッチドッグタイマ :未使用
// スリープモード :未使用
// ウィークプルアップ :未使用
// 割り込み動作 :未使用
// プリ・ポストスケーラ :未使用
// USART :未使用
// CCP :未使用
//
//
// [機能情報]
//
//
// [メモ書き]
// ・16F690には内部クロック微調整のビットが無い(自動調整)
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
__CONFIG(
INTIO //内部クロック生成器 外部出力無し
& WDTDIS //ウォッチドッグタイマOFF
& PWRTDIS //パワーアップタイマOFF
& MCLRDIS //リセット回路使用しない
& UNPROTECT //プログラムのプロテクト プログラムの読み出し禁止OFF
& BORDIS //ブラウンアウトリセット 電源オフ時リセットOFF
& IESODIS //内部・外部スイッチオーバー 動的なクロック周波数切替OFF
& FCMDIS //フェイルセーフクロックモニタ クロック生成器の故障対応OFF
);
//プロトタイプ宣言//
unsigned char get_dipsw(unsigned char resive);
void get_ad();
void white_cyl(unsigned char cyl_moved_direction);
//グローバル変数設定//
unsigned char tmp_a = 0;
unsigned char adcon_port; //現在変換中のAnalogPortを記憶
unsigned char tmp_ad_AN9_back; // AN9のデータコピー用 mode4動作中に操作ボリュームの変更があったことを調べる変数
unsigned char tmp_ad_AN9; // A/D変換後の AN9のデータを記憶 操作ボリューム入力
unsigned char tmp_ad_AN7; // A/D変換後の AN7のデータを記憶 ポテンショメータ左入力
unsigned char tmp_ad_AN8; // A/D変換後の AN8のデータを記憶 ポテンショメータ右入力
//unsigned char tmp_ad_AN3; // A/D変換後の AN3のデータを記憶 トリマVol入力
unsigned char tmp_sum_potentiometer;// ポテンショメータ右・左の内、角度の高い(深い)ものを記録
unsigned char tmp_tmr1; //timer1の10mSec-1Sec変換用バッファ
unsigned char mode_sw = 0; //処理モード分岐用フラグ 0:初回処理 1:手動モード 2:自動待機(自動ボタン点滅) 3:自動モード_刈り取り機動作_目標値設定
// 4:自動モード_目標値へ動作 5:自動モード_時間待ち 6:自動->手動切り替え(異常)時のブザー生成
unsigned char tmp_a; //汎用変数 主にLED点滅用
unsigned char tmp_b; //汎用変数
unsigned char mode2_couter; //mode2からmode3に移行する際に、RA5を2秒間カウントする変数
unsigned char mode5_couter; //mode5で時間計測を行うカウンタ
unsigned char cuttingmachine_position; //刈り取り機の目標値を入れる変数
unsigned int movement_time = 0; //I/Oの出力時間を計測する変数
unsigned char mode5_delay_time; //リレー出力操作周期を指定(0.5-3.5秒)
//メイン関数//
main(void){
PORTA=0b00000000; //全ポート 値リセット
PORTB=0b00000000;
PORTC=0b00000000;
TRISA=0b00111000; //[I/O情報]の通りに設定
TRISB=0b01110000;
TRISC=0b11001100;
//AN7,AN8,AN9をアナログ入力ポートに指定
ANSEL =0b10001000; //[ANS7,ANS6,ANS5,ANS4,ANS3,ANS2,ANS1,ANS0]
ANSELH=0b00000011; //[null,null,null,null,ANS11,ANS10,ANS9,ANS8]
T0CS=0; //タイマ0のクロックを命令クロックにする
TMR0=0; //タイマ0に0を書く
T0IF=0; //タイマ0割り込みフラグビットを0にする
T0IE=0; //タイマ0オーバーフロー割り込みを使用しない
TMR1L=0; //タイマ1に0を書く
TMR1H=0;
T1CKPS0=0; //タイマ1のプリスケーラを1:1にする 01(1:2) 10(1:4) 11(1/8)
T1CKPS1=0;
TMR1CS=0; //タイマ1の動作クロックを命令クロックと同期させる
TMR1ON=1; //タイマ1を動作させる
TMR1IF=0; //タイマ1割り込みフラグビットを0にする
TMR1IE=1; //タイマ1オーバーフロー割り込みを使用する
ADCS0=1; // A/D変換クロックをFosc/8にする
ADCS1=0;
ADCS2=0;
ADFM=0; //変換結果データは左詰にしてADRESHのみ(8bit)使用
ADON=1; //A/Dコンバータ電源on
ADIF=0; //割り込みフラグビットをリセット
ADIE=1; // A/D変換終了割り込みを使用
PEIE=1; //深度割り込みビットを使用できるようにする
GIE=1; //全割り込みフラグビットが立つようにする
IOCA5 = 1; //入力レベル変化割込検出 RA5を検出
//IOCA5 = 1;
//IOCA3 = 1;
tmp_b = PORTA; //portaのデータを読み込み、I/Oバッファを更新する tmp_bデータは特別使用しない
RABIF=0; //フラグビットリセット
RABIE=1; //入力レベル変化割込を使う
white_cyl(0); //シリンダーはブレーキモード
while(1){
// //周期更新エリア//
get_ad(); //4つのアナログ入力値を更新
if(tmp_tmr1 >= 10){ //タイマ1 0.1Sec生成 (プログラム修正ごとにここの値の微調が必要)
tmp_tmr1 = 0;
//0.1Secごとにインクリメントが必要な変数をここに記入 時刻精度は最低
if(tmp_a <=254) tmp_a++;
if((mode2_couter != 0) & (mode2_couter <= 254)) mode2_couter++;
if((mode5_couter != 0) & (mode5_couter <= 254)) mode5_couter++;
if((movement_time != 0) & (movement_time <= 1000)) movement_time++;
}
if(tmp_ad_AN7 <= tmp_ad_AN8) tmp_sum_potentiometer = tmp_ad_AN7; //2つのポテンショの内、角度の低い(浅い)ものを抽出
else tmp_sum_potentiometer = tmp_ad_AN8;
mode5_delay_time = 0; //DIPスイッチ(上位桁RB5(2),RB4(3),RC2(4)下位桁)の値を取得し、リレー出力周期をセットする
if(RB5 == 0)mode5_delay_time += 20;
if(RB4 == 0)mode5_delay_time += 10;
if(RC2 == 0)mode5_delay_time += 5;
// @@ 初回起動エリア @@
if(mode_sw == 0){
movement_time = 0; //mode4にて使用 それ以外では0(動作停止)とする
mode_sw = 2; //手動待機モードへ
}
// @@ 手動モードエリア @@
if(mode_sw == 1){ //手動エリア
/*
movement_time = 0; //mode4にて使用 それ以外では0(動作停止)とする
if(tmp_sum_potentiometer <= 76){ //もし、双方のシリンダが40度(76は実測値)以下ならモード2に移行
mode_sw = 2;
mode2_couter = 0; //押しボタンスイッチ用遅延カウンタ停止
}
RC0 = 0; //リレー出力停止
RA2 = 0; //リレー出力停止
RC4 = 0; //自動モード移行できないことを示すため、照光スイッチを消灯
*/
mode_sw = 2; //強制的にモード2へ
}
// @@ 自動待機(自動ボタン点滅)モードエリア @@
if(mode_sw == 2){ //自動待機(自動ボタン点滅)エリア
movement_time = 0; //mode4にて使用 それ以外では0(動作停止)とする
// if(tmp_sum_potentiometer > 76){ //もし、双方のシリンダが40度(76は実測値)以上ならモード1に戻る
// mode_sw = 1;
// }
if(tmp_a >= 3){
tmp_a = 0;
RC4 = !RC4;
}
if(RA5) mode2_couter = 0; //もし押しボタンスイッチ用遅延カウンタ動作中にボタンが離された場合はカウンタをリセット停止
if(mode2_couter >= 1){ //もし0.1秒以上自動ボタンを押していたら
mode_sw = 3;
mode2_couter = 0; //押しボタンスイッチ用遅延カウンタ動作停止
RC4 = 1; //照光スイッチ 点滅から点灯へ
RC1 = 1; //ブザーON
do DelayMs(100); //押しボタンスイッチを放すまでループ(チャタリングを考慮し、先に時間を稼ぐ)
while(!RA5);
DelayMs(200); //0.2秒間ブザーを鳴らす
// DelayMs(250);
// DelayMs(250);
// DelayMs(250);
RC1 = 0; //ブザーOFF
}
}
// @@ 自動モード_刈り取り機動作_目標値設定モードエリア @@
if(mode_sw == 3){ //自動モード_刈り取り機動作_目標値設定エリア
movement_time = 0; //mode4にて使用 それ以外では0(動作停止)とする
RC4 = 1; //照光スイッチが点灯しているか再投入
// cuttingmachine_position = 42;
tmp_ad_AN9_back = tmp_ad_AN9; //この時点での操作ボリュームの値を記憶
if(tmp_ad_AN9 > 25)cuttingmachine_position = 25 + (tmp_ad_AN9 - 25); //目標値設定 tmp_ad_AN9は10基準(0-38変動)とし (コメント化)
else if(tmp_ad_AN9 < 25)cuttingmachine_position = tmp_ad_AN9; //それ以上なら-10底下げ、以下ならそのまま引き算とする
mode_sw = 4;
cuttingmachine_position -= 5; //目標値を無理やり下げる 201008261435追記
}
// @@ 自動モード_目標値へ動作モードエリア @@
if(mode_sw == 4){ //自動モード_目標値へ動作エリア
RC4 = 1; //照光スイッチが点灯しているか再投入
/* //(コメント化)
if(tmp_sum_potentiometer > 76){ //もし、双方のシリンダが40度(76は実測値)以上ならモード1に戻る
mode_sw = 6;
break;
}
*/
if((tmp_sum_potentiometer - 1) > cuttingmachine_position){
RC0 = 0;
RA2 = 1;
}else if((tmp_sum_potentiometer + 1) < cuttingmachine_position){
RC0 = 1;
RA2 = 0;
}else{
RC0 = 0;
RA2 = 0;
mode_sw = 5;
movement_time = 0; //mode4にて使用 それ以外では0(動作停止)とする
}
if(!RA5){ //自動 -> 手動切り替えフェーズ
DelayMs(1); //チャタリング読み飛ばし用
RC0 = 0; //リレー出力停止
RA2 = 0; //リレー出力停止
RC4 = 0; //照光スイッチ消灯
RC1 = 1; //ブザーON
while(!RA5); //自動ボタンを放すまで待つ
DelayMs(250);
DelayMs(250);
DelayMs(250);
DelayMs(250);
RC1 = 0; //ブザーOFF
mode_sw = 1;
}
if((movement_time == 0) & (RB6 == 0)) movement_time = 1 ; //I/O出力時間計測カウンタ(アップタイマ)
else if(movement_time >= 51){
mode_sw = 6; //もしリレー出力状態が5秒以上続いた場合はエラーとみなし、エラー処理モードへ強制転送
movement_time = 0;
}
}
// @@ 自動モード_時間待ちモードエリア @@
if(mode_sw == 5){ //自動モード_時間待ちエリア
movement_time = 0; //mode4にて使用 それ以外では0(動作停止)とする
RC4 = 1; //照光スイッチが点灯しているか再投入
/* //(コメント化)
if(tmp_sum_potentiometer > 76){ //もし、双方のシリンダが40度(76は実測値)以上ならモード1に戻る
mode_sw = 6;
break;
}
*/
if(mode5_couter == 0) mode5_couter = 1; //遅延カウンタ動作開始
if(mode5_couter >= mode5_delay_time){
mode_sw = 3;
mode5_couter = 0;
}
if(!RA5){ //自動 -> 手動切り替えフェーズ
DelayMs(1); //チャタリング読み飛ばし用
RC0 = 0; //リレー出力停止
RA2 = 0; //リレー出力停止
RC4 = 0; //照光スイッチ消灯
RC1 = 1; //ブザーON
while(!RA5); //自動ボタンを放すまで待つ
DelayMs(250);
DelayMs(250);
DelayMs(250);
DelayMs(250);
RC1 = 0; //ブザーOFF
mode_sw = 1;
}
}
// @@ 自動->手動切り替え(異常)時のブザー生成モードエリア @@
if(mode_sw == 6){ //自動->手動切り替え(異常)時のブザー生成エリア
RC4 = 0; //照光スイッチを消灯
RC0 = 0; //リレー出力停止
RA2 = 0; //リレー出力停止
RC1=1; //ブザーON
DelayMs(160);
RC1=0; //ブザーOFF
DelayMs(160);
RC1=1; //ブザーON
DelayMs(160);
RC1=0; //ブザーOFF
DelayMs(160);
RC1=1; //ブザーON
DelayMs(250);
DelayMs(250);
DelayMs(250);
RC1=0; //ブザーOFF
mode_sw = 1;
}
//割込関数//
interrupt warikomi(){
if(ADIF & ADIE){
ADIF=0;
// A/D変換完了記述エリア
// if(adcon_port==3) tmp_ad_AN3=ADRESH; //AN3の値の更新中ならばAN3のG変数に値を代入
if(adcon_port==7) tmp_ad_AN7=ADRESH; //AN7の値の更新中ならばAN7のG変数に値を代入
if(adcon_port==8) tmp_ad_AN8=ADRESH; //AN8の値の更新中ならばAN8のG変数に値を代入
if(adcon_port==9) tmp_ad_AN9=ADRESH * 0.19 ; //AN4の値の更新中ならばAN9のG変数に値を代入 スケールダウン(256 -> 50) (訂正前0.16-42)
if(tmp_ad_AN9 > 50) tmp_ad_AN9 =50; //スケールダウン失敗時の保護用 //誤作動時にはここが原因となる可能性あり (元が38)
}
if(T0IF & T0IE){
T0IF=0;
//タイマ0オーバーフロー記述エリア
// get_ad(); //256mSec間隔で約5mSec程かけて3つのアナログ入力値を更新
}
if(TMR1IF & TMR1IE){
//タイマ1オーバーフロー記述エリア
TMR1IF=0;
TMR1H = 55535/256; //タイマ1は10mSecタイマ (1uSecごとにインクリメント)
TMR1L = 55535%256;
tmp_tmr1++;
}
if(RABIF & RABIE){
//I/O入力レベル変化割込検出エリア
tmp_b = PORTA; //portaのデータを読み込み、I/Oバッファを更新する tmp_aデータは特別使用しない
RABIF = 0;
if((mode2_couter == 0) & (!RA5)) mode2_couter = 1; //押しボタンスイッチ用遅延カウンタ動作開始
}
}
/*
//DIP SW 処理関数 //
// get_dipsw(DipSwNo.)
// DipSwNo.:1-4のSw番号
// 返送値 :指定Swの論理値(0-1)
unsigned char get_dipsw(unsigned char resive){
unsigned char tmp_dipsw;
switch (resive){
case 1: tmp_dipsw = RB6;
break;
case 2: tmp_dipsw = RB5;
break;
case 3: tmp_dipsw = RB4;
break;
case 4: tmp_dipsw = RC2;
break;
default:tmp_dipsw = 1;
}
return(~tmp_dipsw);
}
*/
//各Portアナログ値更新処理関数 //
// 呼んだ時に tmp_ad_AN7 ,tmp_ad_AN2 ,tmp_ad_AN4の値を更新
// 返送値:無し
void get_ad(){
// adcon_port=3; //AN3の値の更新開始
// CHS0=1; // A/D変換portを指定
// CHS1=1; // 0000:AN0 ,0001:AN1 ,0010:AN2 ,0011:AN3 ,0100:AN4 ,0101:AN5 ,0110:AN6
// CHS2=0; // 0111:AN7 ,1000:AN8 ,1001:AN9 ,1010:AN10 ,1011:AN11
// CHS3=0; // 1100:CVref ,1101:0.6vFixedVoltageReference
// DelayUs(20); //変換ポート移動後は20us以上ホールドコンデンサのチャージ時間を取る
// GODONE=1; // A/D変換開始
// DelayMs(1); // A/D変換割り込みの終了を予想し待つ
adcon_port=7; //AN7の値の更新開始
CHS0=1; // A/D変換portを指定
CHS1=1; // 0000:AN0 ,0001:AN1 ,0010:AN2 ,0011:AN3 ,0100:AN4 ,0101:AN5 ,0110:AN6
CHS2=1; // 0111:AN7 ,1000:AN8 ,1001:AN9 ,1010:AN10 ,1011:AN11
CHS3=0; // 1100:CVref ,1101:0.6vFixedVoltageReference
DelayUs(20); //変換ポート移動後は20us以上ホールドコンデンサのチャージ時間を取る
GODONE=1; // A/D変換開始
DelayMs(1); // A/D変換割り込みの終了を予想し待つ
adcon_port=8; //AN8の値の更新開始
CHS0=0; // A/D変換portを指定
CHS1=0; // 0000:AN0 ,0001:AN1 ,0010:AN2 ,0011:AN3 ,0100:AN4 ,0101:AN5 ,0110:AN6
CHS2=0; // 0111:AN7 ,1000:AN8 ,1001:AN9 ,1010:AN10 ,1011:AN11
CHS3=1; // 1100:CVref ,1101:0.6vFixedVoltageReference
DelayUs(20); //変換ポート移動後は20us以上ホールドコンデンサのチャージ時間を取る
GODONE=1; // A/D変換開始
DelayMs(1); // A/D変換割り込みの終了を予想し待つ
adcon_port=9; //AN9の値の更新開始
CHS0=1; // A/D変換portを指定
CHS1=0; // 0000:AN0 ,0001:AN1 ,0010:AN2 ,0011:AN3 ,0100:AN4 ,0101:AN5 ,0110:AN6
CHS2=0; // 0111:AN7 ,1000:AN8 ,1001:AN9 ,1010:AN10 ,1011:AN11
CHS3=1; // 1100:CVref ,1101:0.6vFixedVoltageReference
DelayUs(20); //変換ポート移動後は20us以上ホールドコンデンサのチャージ時間を取る傾斜
GODONE=1; // A/D変換開始
DelayMs(1); // A/D変換割り込みの終了を予想し待つ
//シリンダー出力処理関数 //
// white_cyl(cylinder_direction)
// 0:ブレーキ 1:A回転 2:B回転
void white_cyl(unsigned char cyl_moved_direction){
switch (cyl_moved_direction){
case 0: RC0=0; //シリンダーブレーキモード
RA2=0;
break;
case 1: RC0=1; //A方向回転モード
RA2=0;
break;
case 2: RC0=0; //B方向回転モード
RA2=1;
break;
default: break;
}
}
どうも動作がおかしい。
外部LEDにてデバッグ作業を半日続けているが、
mode_sw変数に、0〜6以外の変数が代入されている様子。
メインのループ処理の分岐変数のため、まったく動作しなくなる。
例外処理(外部LED点滅)を追記しては消してを繰り返していくうち、mode_swで分岐する処理のif文のどれにも入れていないことがわかった。
この症状が出たのはアナログ入力を追加したときなのだが、mode_sw変数とはなにも係わり合いが無い。
メモリマップレベルでの異常が発生しているような気がするが、当方ではそちらの実験は出来ない。
なんだろう。
北海道 新十津川町 肉の大畠 牛コロコロホルモン
コメントは控えさせて頂きます。

