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

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

PIC16F88を動かす。。。その10(確認のまとめ)

2012-09-12 22:55:28 | PIC16F88

こんばんわ

としぶぅ~です。

 

今日はさっきまで、レンタルした”バトルシップ”を鑑賞してました。

面白かった^^

 

今日は昨日とったデータをまとめようと思います。

こんな感じです。

上記のとおり基準電圧の範囲を縮めればそれだけ解像度が上がることが

わかります。

例えば、8bitで比べると

5V-0V基準の場合

   0℃~-25℃:14分割

   0℃~+25℃:13分割

   +25℃~+100℃:31分割

になります。

1.5V-0V基準の場合

   0℃~-25℃:44分割

   0℃~+25℃:47分割

   +25℃~+100℃:107分割

という感じです。

10bitだとものすごく細かくなることが分かってもらえると思います。

1.5V-0V基準で10bitでソフトつくりますかね。。。。

ちょぅ~精度の高い温度計ができそうです。。。。。こんなに精度いらないって(笑)

 

つぎはがんばってソフトつくりましょうかね^^

 

では今日はこんなところで。。。。おやすみなさい^^/

 

 

 

http://blog.with2.net/link.php?1410783


PIC16F88を動かす。。。その9(考えたことの確認)

2012-09-11 22:47:15 | PIC16F88

こんばんわ

としぶぅ~です。

 

すこしづつすごしやすくなってきましたね。。。

本日は昨日温度センサの取り込みについて考えたことを確認しました。

確認した回路図は、

VR101を+VREF入力に接続してADの基準電圧を供給します。

まずは、現状のデータをとっていきます。

先日と同じように、Pickkit2とMPLABの組み合わせでDEBUGモードで・・・・

基準電圧を電源-VSS(GND)

ANS4に1450mVを供給     → 8bit:4Bh(10bit:12Ch)

 

ANS4に850mVを供給   →  8bit:2Ch(10bit:0B1h)

ANS4に600mVを供給   →  8bit:1Fh(10bit:07Ch)

ANS4に350mVを供給   →  8bit:11h(10bit:046Ch)

次に、基準電圧を+VREF(+1.5V)-VSS(GND) ← +VREFの電圧

ANS4に1450mVを供給   →  8bit:FFh(10bit:3FCh)

ANS4に850mVを供給   →  8bit:94h(10bit:251h)

ANS4に600mVを供給   →  8bit:65h(10bit:195h)

ANS4に350mVを供給   →  8bit:39h(10bit:0E7h)

 

とりあえず今日はデータをとってみました。。。。ちょっと画像ばっかりでうざい?

ま、でも残しとかないと忘れてしまうので。。。^^;

 

+VREFに電圧を電源よりも下げて入れることにより解像度は上がっているように見えます。

本日とったデータの考察は明日にします。。。

画像貼り付けるのに疲れました・・・・・あはは

 

すみません。。。画像のサイズが自由になれば楽なんですが・・・・ちょっと不自由!

 

今日はこの辺にしておきます。

 

では、おやすみなさい^^/

 

 

 


PIC16F88を動かす。。。その8(温度センサについて考える)

2012-09-10 21:30:33 | PIC16F88

こんばんわ
としぶぅ~です。

今日は週の初めなのに疲れ???
なんか力が出ないので早めに帰ってきました。

今日は疲れてるので。。。
考えることだけにします^^;

ADで取り込むLM61BIZについて考えます。

主な仕様は、
 動作規定温度範囲:2.7V~10V
 検出感度:+10mV/℃
 Bグレード精度(-25℃~+85℃)

 Vo=(+10mV/℃ x T℃)+ 600mV
 +85℃ → +1450mV
 +25℃ → +850mV
   0℃ → +600mV
 -25℃ → +350mV

ってな感じです。

PIC16F88の電源電圧が5Vなので、電源基準でADをすると
 8bitで +5V ÷  256 = 0.01953/bit
10bitで +5V ÷ 1024 = 0.00488/bit
となるはず。。。。あってる?(笑)

 8bitA/Dの場合は、1bitあたり19.5mV
10bitA/Dの場合は、1bitあたり 4.9mV
ということになりますが。。。ちょっと解像度があらい。。。。
 8bitだと2℃で1bit動く
10bitだと0.5℃で2bit動くということですね。
よって、ちょ~アバウトな温度計になってしまいますね。。。どうしようか・・・

精度を上げる方法としては、
 ADの電源までの範囲を狭めればいい?
 現状0V~5Vのところを、0V~1.5Vにすれば
 8bitA/Dの場合は、1bitあたり 5.9mV
10bitA/Dの場合は、1bitあたり 1.5mV
となり
 8bitだと0.6℃で1bit動く
10bitだと0.15℃で2bit動くということですね。
かな~り解像度が上がりますよね^^

但し、+REF端子に+1.5Vを入力しなければいけない!
現在+REF端子はLCDのデータで使ってしまっている。。。。

ちょっとどうするか検討しなければ^^;;;

今日は文字だけで。。。。

ではおやすみなさい^^/


PIC16F88を動かす。。。その7(LCD表示関数)

2012-09-09 22:36:35 | PIC16F88

こんばんわ

としぶぅ~です。

大分日中でも過ごしやすくなりましたね。

今日は昼間でもほとんどエアコンいりませんでした。

 

では今日は温度を表示させるためにLCDの関数を追加します。

LCDはSC1602Bの互換品だったと思います。(秋月電子で買ったものです。。。確か)

かな~り昔に動くようにしたソフトをPIC16F88の回路用に修正したものです。

ソフトは、マニュアルに書いてある通りのフローチャートにしてあると思います。(多分)

こんな感じです。

”lcd.c”

//*
//* LCD(SC1602) interface file
//*
//* 以下の機能を供給する
//* lcd_cmd(unsigned char) LCDにコマンドデータを出力する
//* lcd_data(unsigned char) LCDに表示データを出力する
//* lcd_clear(void) 画面をクリアする
//* lcd_puts("ABCD・・・HJ") 文字列を表示する
//* lcd_posyx(y,x) カーソル位置を、行 y、横位置 xにする
//* lcd_init(void) LCDの初期化をする
//*
//*
//* LCD_RS PORTA, 7 ;RS信号
//* LCD_E PORTA, 6 ;E信号
//* LCD_DB PORTA ;PORTA 0-3 → DB4-7(上位4ビット)
//*


#include
#include "delay.h"
#include "lcd.h"

#define LCD_RS RA7
#define LCD_EN RA6


// write a byte to the LCD in 4 bit mode
void lcd_cmd(unsigned char c)
{
unsigned char cdata;
// Making MSB Command Data 4bit
cdata = ((c >> 4) & 0x0f) | (PORTA & 0x70 & 0xb0);
PORTA = cdata; // RS = "H"→”L"
PORTA = cdata | 0x40; // E = "H"→”L"
PORTA = cdata;
// Making LSB Command Data 4bit
cdata = (c & 0x0F) | (PORTA & 0x70 & 0xb0);
PORTA = cdata; // RS = "H"→”L"
PORTA = cdata | 0x40; // E = "H"→”L"
PORTA = cdata;
DelayMs(5);
}

// write one character to the LCD
void lcd_data(unsigned char c)
{
unsigned char cdata;
// Making MSB Data 4bit
cdata = ((c >> 4) & 0x0F) | (PORTA & 0xf0) | 0x80;
PORTA = cdata; // RS = "L"→”H"
PORTA = cdata | 0x40; // E = "H"→”L"
PORTA = cdata;
// Making LSB Data 4bit
cdata = (c & 0x0F) | (PORTA & 0xf0) | 0x80;
PORTA = cdata; // RS = "L"→”H"
PORTA = cdata | 0x40; // E = "H"→”L"
PORTA = cdata;
DelayMs(5);
}

// Clear and home the LCD
void lcd_clear(void)
{
lcd_cmd(0x1);
DelayMs(5);
}

// write a string of chars to the LCD
void lcd_puts(const char * s)
{
while(*s)
lcd_data(*s++);
}

// Go to the specified position
void lcd_posyx(unsigned char ypos,unsigned char xpos)
{
unsigned char pcode;

switch(ypos & 0x03){
case 0: pcode=0x80;
break;
case 1: pcode=0xC0;
break;
case 2: pcode=0x94;
break;
case 3: pcode=0xD4;
break;
}
lcd_cmd(pcode += xpos);
}

// initialise the LCD - put into 4 bit mode
void lcd_init(void)
{

// Initalize コマンドを2~3回書き込まないとうまく動かない(2Lineモードにならなかった))
lcd_cmd(0x2c); // 4 bit mode, 2-LineMode, 5x8 font
DelayUs(40);
lcd_cmd(0x2c); // 4 bit mode, 2-LineMode, 5x8 font
DelayUs(40);
lcd_cmd(0x0c); // display on, blink curson on
DelayUs(40);
lcd_clear(); // display off
DelayMs(2);
lcd_cmd(0x06); // entry mode
}

 

次にヘッダファイルです。

”lcd.h”

/*
LCD interface header file
See lcd.c for more info
*/

/* write a byte command to the LCD in 4 bit mode */

extern void lcd_cmd(unsigned char);

/* write a byte data to the LCD in 4 bit mode */

extern void lcd_data(unsigned char);

/* Clear and home the LCD */

extern void lcd_clear(void);

/* write a string of characters to the LCD */

extern void lcd_puts(const char * s);

/* Go to the specified position */

extern void lcd_posyx(unsigned char,unsigned char);

/* intialize the LCD - call before anything else */

extern void lcd_init(void);

 

とりあえず、表示できることを確認しています。

(改造すれば他のマイコンにも使えます。。。。先日はNXPのマイコンにも実装しました。)

 

LCDは、http://akizukidenshi.com/catalog/g/gP-00040/ です。

上の関数は使っても問題ないですが。。。くれぐれも理解してからということで。。。

今日は簡単ですがこんなところで・・・

 

それではおやすみなさい!

 

 


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に表示する関数を組み込もうと思います。

 

それでは今日はこの辺で

 

(^^)/~