/*---------------------------------------------------------------------------- * File: JoyStick001.c * Copyright : VividHobby * * JoyStic Remote Controller * Starnew versionAD読み込み表示完了 v001 * JoyStickの稼動範囲の補正 v002 * その2 v003 * その3 x_centの読み込みがERR v004 * x, yの中央値を個別に指定するとAD変換は動作するが、読み取りにすると *  動作しない。 * * 問題解決の試み1ad_val直読みではOK v005 * 原因判明 float変数の使い方が間違い v006 * AD結果を10ビットで表示 v007 * ADや中立値の決定は10回読み込んで平均 v008 * * * * * * * * Created on 2016/06/01, 17:31 */ //------------------------------------------------------------------------- // プログラム初期設定 //------------------------------------------------------------------------- #include #include #include #pragma config FOSC = HS //高速オシレーター(4MHz以上)使用 #pragma config WDTE = OFF //ウォッチドッグタイマーOFF #pragma config CP = OFF //コードプロテクションOFF #pragma config PWRTE = ON //パワーアップタイマーON #pragma config LVP = OFF//PIC16F84Aでは未サポート //PICのクロック設定 #define _XTAL_FREQ 20000000 //PICのクロックをHzで設定(20MHz) //------------------------------------- // SWスイッチ用ポートの設定 //------------------------------------- #define sw0 RC0 // RC0にsw0を設定 #define sw1 RC1 // RC1にsw1を設定 //------------------------------------------------------------------------ // 変数初期設定 //------------------------------------------------------------------------ int ad_val = 0; //AD変換結果格納 int ad_x = 0, ad_y = 0; //AD変換後、補正後の最終x,y格納場所 (0-1023) int ad_h = 0, ad_l = 0; //AD変換結果レジスタの上位下位の格納 int x_max = 0, x_cent = 0, x_min = 1023, y_max = 0, y_cent = 0, y_min = 1023; //JoyStickの位置の最大最小中央値初期化 int i, j, temp = 0; // Loop counter float x_h = 0, x_l = 0, y_h = 0, y_l = 0; //AD変換正規化の補正値(X,Yそれぞれ上位と下位) float calc = 0, calc2=0; unsigned char ad_ch = 0; //AD変換ch指定(0-5) unsigned char ad_para_temp = 0b10000001; //AD変換パラメータのテンプレート //------------------------------------------------------------------------ // 関数定義 //------------------------------------------------------------------------ void pic_init_16f876(void); void ad_conv(void); void ad_limit(void); void ad_cent(void); void correction(void); void ad_actual(void); //------------------------------------------------------------------------- // メインプログラム //------------------------------------------------------------------------- main() { pic_init_16f876(); // PIC初期化。 ADは2ch分設定(PCFG=0100) //---------------------------------------------------------------- // 変数初期値設定 //--------------------------------------------------------------- //---------------------------------------------------------------- // メイン処理開始 //---------------------------------------------------------------- //----------------- // AD変換準備 //----------------- __delay_ms(1000); ad_cent(); // ジョイスティックの中央値セット PORTB = 0; // ジョイスティック中央値読み込み完了の表示 __delay_ms(1000); for (i = 1; i <= 500; i++) { ad_limit(); // ジョイスティックのX,Yそれぞれの最大最小値を得る __delay_ms(5); } correction(); // AD変換補正値を計算し、セット while (1) { ad_actual(); // AD変換を実施し、値を補正。結果は、ad_x と ad_yにセット(10ビット) //AD結果10ビットを表示のために上位8ビットに if (sw0 == 0) { PORTC = ~(ad_x >> 6); PORTB = ~ad_x; //表示が01反転の為 } else { PORTC = ~(ad_y >> 6); PORTB = ~ad_y; } } } //=============================== Main prog 終了 ============================== //================== 以下 関数定義 ============================================ //------------------------------------------------------------------------- // PIC 16F876 初期設定(ポート、AD、割り込み) //------------------------------------------------------------------------- void pic_init_16f876(void) { //--------------------------------------------- // PICのPORT設定の初期化 AD変換RA0ポートに設定 //--------------------------------------------- //PICのポート設定 ADCON0 = 0b10000001; //アナログ使用AD on CHS0 = 0; // 以下の3ビットでADの使用chを設定(0-4ch) CHS1 = 0; CHS2 = 0; //ADはAN0, AN1, AN3 結果はADRESHに左寄せ8ビット ADCON1 = 0b10000100; //For A/D0 & degital I/O(PCFG=0100) //結果は右詰め(10ビット使用) TRISA = 0b00000011; // A/D変換はRA0で行うのでRA0を入力に設定 TRISB = 0b00000000; TRISC = 0b00000011; // スイッチsw0とsw1を接続 PORTA = 0b11111111; // ポートの初期値を設定する(Hで通常、LでON) PORTB = 0b11111111; PORTC = 0b11111111; //---------------------------------------------------------------- // ==== TMR は未使用 ==== // TMR0設定 // TRM0 setting 割り込み使用、プリスケーラ1/32設定@20MHz // 割り込みは約1.6384 msec毎に発生する //---------------------------------------------------------------- OPTION_REG = 0b10000100; /// Prescaller 1/32 (1.6384 msec full count) INTCON = 0b00100000; GIE = 0; // 全体割り込み禁止 T0IE = 0; // TMR0 中断 T0IF = 0; // TMR0 割り込みフラッグクリア } //------------------------------------------------------------------- // ad_chに変換するADのchをセットしAD変換を実行。結果をad_valに代入する // AD変換結果は0-1023 (補正はなし。純粋にADを実行) //------------------------------------------------------------------- void ad_conv(void) { ad_val = 0; for(j = 1; j <= 10; j++){ //AD変換50回を平均する ADCON0 = ad_para_temp | (ad_ch << 3); //ADのchを指定 __delay_us(20); // 20usecの準備待ち GO = 1; // AD変換開始 while (GO) { // GOビットが1の間待つ(0になるまで待つ) } temp = ADRESH; ad_h = temp << 8; //高位値は256倍する ad_l = ADRESL; ad_val = ad_val + ad_h + ad_l;//低位値と加算してAD結果10ビットを得る __delay_ms(1); } ad_val = ad_val / 10; } //..................................................................... // AD変換の考え方 // VRのAD変換値は、かならずしも0-1023(10bit)にならないので、X/Y値それぞれの // 最小値、最大値を読み取り、中間値とその差をフルスケール512で除して、係数とする //..................................................................... //--------------------------------------------------------------------- // AD変換後のX,Y値の最大最小を求め、正規化を行う //--------------------------------------------------------------------- void ad_limit(void) { ad_ch = 0; // AD ch0 ad_conv(); // Get AD value if (ad_val >= x_max) x_max = ad_val; if (ad_val <= x_min) x_min = ad_val; ad_ch = 1; // AD ch1 ad_conv(); // Get AD value if (ad_val >= y_max) y_max = ad_val; if (ad_val <= y_min) y_min = ad_val; } //--- 注意 -------------------------------------------------------------- // 読み取ったX,Yの最大最小中央値を元に // X,Yの補正係数を計算する x_h等とcalcはfloat型変数 //----------------------------------------------------------------------- void correction(void) { calc = x_max - x_cent; x_h = 512 / calc; calc = x_cent - x_min; x_l = 512 / calc; calc = y_max - y_cent; y_h = 512 / calc; calc = y_cent - y_min; y_l = 512 / calc; } //------------------------------------------------------------------------ // 補正値を元にして // AD変換を事項して、結果を補正する 最終結果 ad_x と ad_y //------------------------------------------------------------------------ void ad_actual(void) { ad_ch = 0; // AD ch0 ad_conv(); calc = ad_val - x_cent; calc2 = ad_val -x_min; if (ad_val >= x_cent) { ad_x = x_cent + (calc * x_h); } else { ad_x = (calc2 * x_l); } if (ad_x <= 0) ad_x = 0; if (ad_x >= 1023) ad_x = 1023; ad_ch = 1; // AD ch1 ad_conv(); // Get AD value calc = ad_val - y_cent; calc2 = ad_val -y_min; if (ad_val >= y_cent) { ad_y = y_cent + (calc * y_h); } else { ad_y = (calc2 * y_l); } if (ad_y <= 0) ad_y = 0; if (ad_y >= 1023) ad_y = 1023; } //--------------------------------------------------------------------- // JoyStickの中立X,Y値のを求め、補正を行う // 指を離した状態のJSの位置を10回読み込んで平均する //--------------------------------------------------------------------- void ad_cent(void) { x_cent = 0; y_cent = 0; ad_ch = 0; // AD ch0 for(i = 1; i <= 10; i ++){ ad_conv(); // Get AD value x_cent = x_cent + ad_val; } x_cent = x_cent / 10; ad_ch = 1; // AD ch1 for (i = 1; i <= 10; i ++){ ad_conv(); // Get AD value y_cent = y_cent + ad_val; } y_cent = y_cent / 10; } //--------------------------- End of Program ----------------------------------}