としぶぅ~の「工作部屋」...毎日少しのお勉強

趣味・関心事を書いていこうと思います。

PIC16F88を動かす。。。その6(AD動作確認)

2012-09-08 16:42:10 | PIC16F88

こんにちわ

としぶぅ~です。

昨日は20年来の知り合いと飲みに行ったのでお休みしました。

 

本日は、先日書きましたADの動作確認を行いました。

とりあえず動くように作ったソフトはこんな感じです。

”ad.c”

/*================================================================================
ADプログラム
File Name : ad.c
Target Compiler: HI-TECH C PRO(Lite MODE)
Verion : 1.0
================================================================================ */
#include    ←必要
#include "ad.h"     ←必要
#include "delay.h"   ←必要

//AD機能とポートの設定
void adinit(unsigned char ansel)
{

/**************************************************
使用するADポートの設定を行う
ansel: bit0:ANS0(RA0)
bit1:ANS1(RA1)
bit2:ANS2(RA2)
bit3:ANS3(RA3)
bit4:ANS4(RA4)
bit5:ANS5(RB6)
bit6:ANS6(RB7)
bit7:
**************************************************/


TRISA=TRISA | 0x10; //ADポート(RA4)を入力設定にする
ANSEL=ansel;       //ADコンバータの設定 ANS0-7

ADON=1;          //ADコンバータ機能の許可
ADIE=0;           //AD割り込み不許可

}

//ad Convert(8bit)
unsigned char ad4()
{
/*************************************************
channel:AN4
基準電圧:電源電圧を使用
AD変換clock:8MHz/16
ADFM=0 Leftjustified
変換時間:
**************************************************/
unsigned char temp = 10;

//設定
ADCON1=0x40; //0110 0000 A/D結果は左詰め,FOSC/16,A/D基準電圧:+Vdd-VSS
ADCON0=0x61; //01xx x001 FOSC/16,ANS4,A/D Status(INPUT),A/D-ON

DelayUs(50); /* Delay関数使用 : 安定待ち */

//AD変換開始
GO_DONE=1;

//変換終了待ち
while(GO_DONE==1){}

//変換結果処理
return(ADRESH);
}

次はヘッダファイル

”ad.h”

 

extern void adinit(unsigned char ansel);
extern unsigned char ad4();

簡単ですが。。。こんな感じです。

後、時間待ち用にDelayも追加しています。

(これは何かの書籍にあったものをそのまま使用しています。たしか・・・トラ技だっけ??)

”delay.c”

//*
//* Delay functions
//* See delay.h for details
//*
//* Make sure this code is compiled with full optimization!!!
//*

#include "delay.h"

void
DelayMs(unsigned char cnt)
{
#if XTAL_FREQ
do {
DelayUs(996);
} while(--cnt);
#endif

#if XTAL_FREQ > 2MHZ
unsigned char i;
do {
i = 4;
do {
DelayUs(250);
} while(--i);
} while(--cnt);
#endif
}

次はヘッダファイル

”delay.h”

/*
* Delay functions for HI-TECH C on the PIC
*
* Functions available:
* DelayUs(x) Delay specified number of microseconds
* DelayMs(x) Delay specified number of milliseconds
*
* Note that there are range limits: x must not exceed 255 - for xtal
* frequencies > 12MHz the range for DelayUs is even smaller.
* To use DelayUs it is only necessary to include this file; to use
* DelayMs you must include delay.c in your project.
*
*/

/* Set the crystal frequency in the CPP predefined symbols list in
HPDPIC, or on the PICC commmand line, e.g.
picc -DXTAL_FREQ=4MHZ

or
picc -DXTAL_FREQ=100KHZ

Note that this is the crystal frequency, the CPU clock is
divided by 4.

* MAKE SURE this code is compiled with full optimization!!!

*/

#ifndef XTAL_FREQ
#define XTAL_FREQ 4MHZ /* Crystal frequency in MHz */
#endif

#define MHZ *1000L /* number of kHz in a MHz */
#define KHZ *1 /* number of kHz in a kHz */

#if XTAL_FREQ >= 12MHZ

#define DelayUs(x) { unsigned char _dcnt; \
_dcnt = (x)*((XTAL_FREQ)/(12MHZ)); \
while(--_dcnt != 0) \
continue; }
#else

#define DelayUs(x) { unsigned char _dcnt; \
_dcnt = (x)/((12MHZ)/(XTAL_FREQ))|1; \
while(--_dcnt != 0) \
continue; }
#endif

extern void DelayMs(unsigned char);

 次にテンプレートにも追加します。

”main.c"

/*================================================================================
Templateプログラム
タイマー割り込みを使って時間をカウントして処理を時分割させる
File Name : main.c
Target Compiler: HI-TECH C PRO(Lite MODE)
Verion : 1.0
================================================================================ */
//PIC用の定義ファイルのインクルード
//HI-TECH Cでは、必ず指定する
#include
#include "ad.h" //AD用の関数(20120908追加)
#include "delay.h" //Delay用関数(20120908追加)

//コンフィグレーションメモリの設定
__CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & MCLRE_OFF & CPD_OFF & BOREN_OFF & LVP_OFF & CP_OFF & FCMEN_OFF & IESO_OFF);


//タイマの再設定値を定義
// 2000cycle@(8MHz / 4) == 1ms
// そこからTimer1再設定に要するサイクルを引いたもの
#define WAIT_CYCLE (2000-5)
#define TMR1H_INIT ((unsigned char)(((unsigned short)(65536-WAIT_CYCLE))>>8))
#define TMR1L_INIT ((unsigned char)(((unsigned short)(65536-WAIT_CYCLE))&0x00ff))

//ビット操作命令のマクロを定義
#define clear_bit( reg, bitNumb ) ((reg) &= ~(1 << (bitNumb))) //指定されたビットをクリア
#define set_bit( reg, bitNumb ) ((reg) |= (1 << (bitNumb))) //指定されたビットをセット
#define test_bit( reg, bitNumb ) ((reg) & (1 << (bitNumb))) //指定されたビットをテスト

unsigned char tmr_1ms;
unsigned char tmr_4ms;
unsigned char tmr_4ms_up;
unsigned char tmr_cnt_up;
unsigned char ad_data; //(20120908追加)

//割り込み関数
//1/100秒の、タイマのオーバーフロー割り込みで、計測値のインクリメントと、スイッチの確認を行う
void interrupt f_int( void )
{
//タイマ割り込みかどうかをチェックして、タイマ割り込み以外の場合は、処理をしない
if(TMR1IF) {
//タイマの値を再設定し、次の割り込みが1/1000秒後に発生するように設定する
TMR1H = TMR1H_INIT;
TMR1L = TMR1L_INIT;
TMR1IF=0; //タイマ1の割り込みフラグをクリアする


tmr_4ms++; //10msごとのカウンタをインクリメント
if(tmr_4ms >= 4){
tmr_4ms = 0;
tmr_4ms_up = 1;
tmr_cnt_up++;
//PORTB 0bitをon/offして4msでtmr_cnt_upが4msになっていることを確認する。
if(test_bit(PORTB,0)){
clear_bit(PORTB,0);
}else{
set_bit(PORTB,0);
}
}
}
}


//ハードウェアの初期化
//使用する回路に合わせて、I/Oポートの方向などを設定する
void IoInit(void)
{
OSCCON = 0x70; //CLK=8MHzに設定する

//ポートの設定
TRISA = 0b00010000; //ポートAは使用しないが、出力に設定 PORTA-bit3=SW入力
TRISB = 0b00000000; //ポートBは使用しないが、出力に設定
PORTA = 0; //ポートAの初期値を0にする
PORTB = 0; //ポートBの初期値を0にする
ANSEL = 0b00000000; //アナログモードは使用しないので、0を指定
}


//タイマ1の初期化
void Tmr1Init(void)
{
T1CON = 0x00; //プリスケーラを、内部クロック、1:1に設定
TMR1H = 0; //タイマ1の初期値を0にする
TMR1L = 0;
TMR1IF = 0; //割り込みフラグをクリアする
//タイマ1割込を有効にする
TMR1IE = 1;
PEIE = 1;
//グローバルの割り込み制御ビットを有効にする
GIE = 1;
}

//メインルーチン
void main( void )
{

unsigned char ansel;

IoInit(); // I/Oポートの初期化
Tmr1Init(); // タイマ1の初期化
ansel = 0x10; // AD4を指定(20120908追加)
adinit(ansel); // RA4をAD4ポートとして初期化する(20120908追加)

//タイマ周期が1/100秒になるように、初期化する
TMR1H = TMR1H_INIT;
TMR1L = TMR1L_INIT;
//時間のカウンタの初期化
tmr_1ms = 0;
tmr_4ms = 0;
tmr_4ms_up = 0;
tmr_cnt_up = 0;
//タイマ1を開始する
TMR1ON=1;

//無限ループ
while(1){

if(tmr_4ms_up == 1){
tmr_4ms_up = 0;
switch(tmr_cnt_up){
case 0: ad_data = ad4(); //処理1 ADを実施(20120908追加)
break;
case 1: //処理2
break;
case 2: //処理3
break;
case 3: //処理4
break;
case 4: //処理5
break;
}
}

//PORTB 3bitをon/offしてプログラムの1周期がどれくらいになるかを確認する。
if(test_bit(PORTB,3)){
clear_bit(PORTB,3);
}else{
set_bit(PORTB,3);
}
}
}

赤字の部分が追加が必要なところです。

それでは下記のラインにブレイクポイントをしかけて、その時の取り込み

レジスタの状態を確認して、供給電圧に応じた取り込みができているかを

確認してみます。

case 0: ad_data = ad4(); //処理1 ADを実施(20120908追加)

 ※ここにブレイクポイントをしかけます

とりあえず3段階で電圧を変更します。(下記のボリュームを回して変更する)

 

また、A/Dの取り込み値は、MPLABとPickit2の組み合わせでデバッグモードでレジスタの内容を

確認したいと思います。

 

最大電圧値:4.809V 

ブレイクポイントで止めてレジスタを確認

4.809V入力で、ほぼMAXのFF80H左づめなので、3FEH最下位bitは、”0”になっています。

8bitで取り込むつもりなので、下位2bitは無視するのでFFHとなりますので問題ないですね。。。

 

中間電圧値:2.193V

2.193V入力で、ほぼMAXの7480H左づめなので、1D2H最下位bitは、”0”になっています。

下位2bitは無視するので74Hとなります。

MAX電圧が4.8Vなので4.8V/256(8bit)→1bitあたり0.01875Vとなります。

74H=116なので、0.01875 X 116 = 2.175Vとなります。

多少誤差がありますが、こんなもんでしょうかね。。。8bitなので問題ないと思います。

※誤差とは測定器とか。。。いろいろ含めての誤差を示します。。。

最小電圧値:0.000V

ほぼ0V入力で、ほぼMAXの0000H左づめなので000H。

最低電圧は000Hで問題なし。

 

ADは問題なく動作しているようです。

これで温度センサを取り付けてもA/Dできるということがわかりました。

その前に、次回は、A/Dした内容をLCDに表示する関数を組み込もうと思います。

 

それでは今日はこの辺で

 

(^^)/~