2015年6月 2日 (火)

PICのお勉強(37) C言語編 12F683でA/D変換

20150602 8ピンPICの定番,12F683でA/D変換をやってみました。
PICのお勉強(29)で16F88を使ってやったことを12f683に移植しただけですな。
10kΩVRを使って,12f683のGP4/AN3に0~3Vの電圧を入力,これを10bitのデジタル値に変換して,GP0に接続したLEDの点滅周期を変えています。

HI-TECH Cで書いたソースとhexファイルはコレ↓です。
「lesson37.c」をダウンロード
「lesson37.hex」をダウンロード

12f683_ad 16F88との違いは,ANSELレジスタやTRISIOレジスタの設定くらいでしょうか。詳細はこちらで確認して下さい。
最初,4ピンのGP3がAN3だと勘違いしていて,GP3にアナログ電圧を入力し,「プログラムは間違ってないはずなのに,全然動かないじゃないかー」としばらく悩みました(笑) この失敗は誰もがやるんじゃないかしらん。僕だけ?

ソースも貼っておきますね。

/**************************************
12F683 HI-TECH C v.9.83
GP4/AN3の入力をA/D変換,GP0のLED点滅周期変える
**************************************/

#include <htc.h>
__CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & BOREN_ON & MCLRE_OFF & CP_OFF & IESO_OFF & FCMEN_OFF);
#define _XTAL_FREQ 1000000 // PICのクロックは1MHz

unsigned int adconv();
unsigned int tmp;
unsigned int i;

void main(void)
{
OSCCON = 0b1000000; // 内蔵OSC 1MHz
ANSEL = 0b00001000; // GP4/AN3がアナログ入力,他はデジタル
CMCON0 = 0b00000111; // コンパレータを使わない
TRISIO = 0b00001000; // GP4/AN3は入力,その他は出力

while (1)
{
tmp = adconv();
GP0 = 1;
for(i = 0; i __delay_ms(2);
}
GP0 = 0;
for(i = 0; i __delay_ms(2);
}
}
}

unsigned int adconv()
{
ADCON0 = 0b10001101; //右詰,基準電圧はVdd,GP4/AN3の入力をA/D変換
__delay_us(25);
GO=1;
while(GO);
return (ADRESH<<8)+ADRESL;
}

| | コメント (0) | トラックバック (0)

2015年5月15日 (金)

UVレジンでLEDイルミネーション (2)

20150515 UVレジンで作ったLEDイルミをPIC12F683で点滅させてみました。
話の流れでいくとIchigoJamで光らせることになるところですが,LEDイルミを5個も作っちゃったので,久しぶりにPICでLチカです。
 これまで「PICのお勉強」では,16F84Aと16F88を使ってきましたが,定番の8ピンPIC,12F683を初めて使ってみました。小さくて安価なPICですが,これはこれでなかなか魅力的なやつです。単3電池2本で動くのもいいですね。

12f683_led_5 回路図はごく平凡なもので,GP0,GP1,GP2,GP4,GP5の5つにLEDをつなぎます。GP3は入力専用だから使えないんですね。
 今後のお勉強用に,12F683のテストボードを作って他に流用できるようにしてあります。PICkitを直接つないで書き込めるようにピンヘッダも取り付けてみました。
ソースはこんな↓具合です。GPIOに,LEDの点灯・消灯パターンを送って点滅させています。

/**************************************
12F683 HI-TECH C v.9.83
GP0~GP2,GP4,GP5のLED順次点灯
**************************************/

#include <htc.h>
__CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & BOREN_ON & MCLRE_OFF & CP_OFF & IESO_OFF & FCMEN_OFF);
#define _XTAL_FREQ 1000000 // PICのクロックは1MHz

void main(void)
{
OSCCON = 1000000; // 内蔵OSC 1MHz
ANSEL = 0b00000000; // デジタル
CMCON0 = 0b00000111; //コンパレータを使わない
TRISIO = 0b00001000; //GP3は入力,その他は出力

while (1)
{
GPIO = 0b00000001; //GP0点灯,他は消灯
__delay_ms(300);
GPIO = 0b00000010; //GP1点灯,他は消灯
__delay_ms(300);
GPIO = 0b00000100; //GP2点灯,他は消灯
__delay_ms(300);
GPIO = 0b00010000; //GP4点灯,他は消灯
__delay_ms(300);
GPIO = 0b00100000; //GP5点灯,他は消灯
__delay_ms(300);
}
}

HI-TECH Cで書いたソースとhexファイルはこちら↓
「lesson36.c」をダウンロード
「lesson36.hex」をダウンロード

 

| | コメント (0) | トラックバック (0)

2014年10月 5日 (日)

PICのお勉強(35) C言語編 PWMでサーボモータを動かす

Pic16f88 16F88のPWM機能を使ってサーボモーターを動かしてみました。
まだ分からないことがたくさんあるのですが、なんとか動いてるようなのでソースを公開します→ lesson35.c
 モーターは秋月で買ったコレですが、まあ何でも大丈夫でしょう。電流をたくさん喰うので、マイコン用とは別に5V電源を用意します。

 サーボモータを動かすためにPWM周期を20ms程度に設定します。(このサイトで勉強しました)
内蔵クロックを1MHz,PR2 を 255,TMR2 プリスケーラ を16 とすると、


命令サイクル:(1s/1MHz)×4クロック = 4μs
PWM周期:4μs×(255+1)×16 = 16,384μs (= 16.384ms)
PWM周期16.4msだとちょっと短いかなあと思いましたが、これで大丈夫みたい。

あとはパルス幅を決めるCCPR1Lの値を指定してやればいいんだけど、これは試行錯誤で10,25,40という値にたどり着きました。これでサーボはだいたい-90度、0度、+90度になりました。
パルス幅を計算してみると、
CCPR1L=10 のとき、4×16×10 = 640μs (=0.64ms)
CCPR1L=25 のとき、4×16×25 = 1,600μs (=1.60ms)
CCPR1L=40のとき、 4×16×40 = 2,560μs (=2.56ms)
となるんだけど、これで計算は合ってるのかなあ。
PICの解説本やWebサイトを見てみると「パルス幅を1.0ms、1.5ms、2.0msにする」なんて書いてあるんだけどね。

/**************************************
16F88 HI-TECH C v.9.83
PWM でサーボモータを動かす
**************************************/

#define _LEGACY_HEADERS
#include

__CONFIG(CCPRB3 & DEBUGDIS & LVPDIS & BOREN & MCLRDIS & PWRTEN & WDTDIS & INTIO);

#define _XTAL_FREQ 1000000 // PICのクロックを1MHz

void main(void)
{
OSCCON = 1000000; // 内蔵OSC 1MHz
ANSEL = 0b00000000; // デジタル
TRISA = 0b11111111; // すべて入力
TRISB = 0b11110111; // BR3は出力
PORTA = 0b00000000;
PORTB = 0b00000000;

CCP1CON = 0b00001100; // PWMモードにする
T2CON = 0b00000111; // プリスケール16
PR2 = 255; // PWM周期
CCPR1L=25; // 中央

while (1)
{
CCPR1L=10;
__delay_ms(1000);
CCPR1L=25;
__delay_ms(1000);
CCPR1L=40;
__delay_ms(1000);
CCPR1L=25;
__delay_ms(1000);
}
}


| | コメント (0) | トラックバック (0)

2014年4月 6日 (日)

秋月電子/新居浜高専PICマイコン学習キット Ver.2

Akizuki_pic_2 秋月電子から3月に発売になったばかりの新居浜高専PICマイコン学習キット Ver.2 を作ってみました。
Ver.1は,PIC16F84Aでしたが,このVer.2は16F886にアップグレード。より多くの機能を使えるようになりました。
PICkit3を接続できるソケットがあり、新たに作ったソフトを書き込む事が容易に出来ますし,すでに16種類の機能がプログラム済みですから,組み立てればすぐに遊べます。
サンプルプログラムは,
・デジタル時計
・2進数のカウント
・Wave
・電子ピアノ
・タッチアラーム
・電子すず虫
・イリュージョンライト
・キャンドルライト
・もぐらたたき
・ミニテルミン
・目覚まし鳥
・電子サイコロ
・音スイッチ
・A/Dコンバータ
・RCサーボコントロール
・タイマー
の16種類。これは楽しめます。

| | コメント (0) | トラックバック (0)

2012年11月 3日 (土)

PICのお勉強(34) C言語編 デジットで買った10桁7セグLCD

7lcd 先日デジットで買ったジャンクの10桁7segLCD(200円)がとりあえず使えるようになりました。
A/D変換で簡易な電圧計(単位はmV)にしただけですが,ちょっとした表示用にこのLCDは使えますね。1個200円という,お手頃価格もうれしいですな。
Disit7segldc ピン配置くらいしか書かれてない簡単なデータシートしかありませんでしたから,ネットで検索してみるとこんなページを見つけたので,ソースを頂戴して,HI-TECH C用に書き換えてみました。
ソースはこれ→ lesson34.c
 lcd7seg_outという文字列表示関数がうまく動かなかったので,使い慣れないポインタを使って,なんとか切り抜けました。まだまだ勉強が足りないなー。

| | コメント (0) | トラックバック (0)

2012年8月20日 (月)

PIC16F84Aでブレークアウト・ゲーム

Breakoutgame 昨日,PICマイコン16F84Aたった1個でできているブレークアウト・ゲーム(ブロック崩し)を作ってみました。
 もちろん僕のオリジナル作品ではなく(^^:)エレキジャックNo.2の「PICでテレビ・ゲームを作ってみよう!」の回路とプログラムをそのまま使っただけですが,1個250円のPICマイコンでTVゲームを作れるなんてすごいですねー。
 ただ,ココにあるBREAKOUT.HEXだと,ハイスコアが記録されません。ASMファイルをちょっと書き換えてビルドし直したコレならバッチリです。この方の記事を参考にしました。感謝。


液晶テレビだからなのか,残像が気になります。ブラウン管のテレビ,もううちにないしなー(^^;)

| | コメント (0) | トラックバック (0)

2012年7月22日 (日)

PICのお勉強(33) C言語編 LM35DZの出力をオペアンプで5倍にしてみる

Lm358n PIC16F88+温度センサLM35DZの温度計の話の続きです。
 気温が28.6℃だとLM35DZの出力が286mVなのですが,AD変換の分解能が約5mVですから,温度の分解能も0.5℃になってしまいます。これではつまらないので,0.1℃単位で温度表示できるように,温度センサの出力をオペアンプで5倍に増幅してやりました。
Lm358 LM358Nという1個20円のオペアンプを使いました。ソースは,前回のやつの
tmp=adconv()*4.53; ってとこを
tmp=adconv(); と変えただけです。
10kVRで,表示温度の微調整ができます。これは結構実用的なものができたかも(^-^)

| | コメント (0) | トラックバック (0)

2012年7月21日 (土)

PICのお勉強(32) C言語編 LM35DZで測った温度を7セグLEDに表示する

Lm35dz7seg 温度センサLM35DZの出力をPIC16F88でAD変換して,3桁の7セグLEDに表示してみました。
この7セグLEDは,ダイナミックドライブ用に内部で配線されてて11ピンのものです。こりゃ便利ですね。
ソースはこれ→lesson32.c

 7セグLEDへの表示は,TMR0割り込みで実行していますが,小数点をつけるのに少々苦労しました。
結局,小数点つきの0~9の表示用数字データを作って配列に入れておき,これを使うことにしました。PORTB=p[tmp1+10]なんてあたりに苦労のあとが忍ばれますなあ(笑)
7seg3 気温が28.5℃だと,AD変換の結果,tmpという変数に285という値が入りますから,これを100で割ってから,さらに10で割ったときの余りを求めて「2」という数字を得て,tmpを10で割ってからさらに10で割ったときの余りを求めて「8」という数字を得ます。最後にtmpを10で割ったときの余りを求めて「5」という数字を得ます。これで3桁ぶんの数字が得られるのです。LCDの場合と違ってめんどくさいですねー。

/**************************************
16F88 HI-TECH C v.9.83
温度計 LM35DZをRA0(AN0)に接続 7segLED表示
**************************************/

#define _LEGACY_HEADERS
#include "pic.h"
#include "stdlib.h"
#define _XTAL_FREQ 8000000
__CONFIG(DEBUGDIS & LVPDIS & BORDIS & MCLRDIS & PWRTEN & WDTDIS & INTIO);
__CONFIG(FCMDIS & IESODIS);

unsigned int adconv(),tmp,tmp0,tmp1,tmp2;
unsigned char i=0;
unsigned int p[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F, //0,1,2,3,4,5,6,7,8,9
0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0xa7,0xff,0xef}; //0.,1.,2.,3.,4.,5.,6.,7.,8.,9.

static void interrupt warikomi(void)//割り込み処理で7セグLED表示
{
TMR0IF = 0; //TMR0割り込み禁止
i++;
if(i==3){
i=0;
}

switch(i){
case 0:
PORTA=0b00011000;
PORTB=p[tmp0];
break;
case 1:
PORTA=0b00010100;
PORTB=p[tmp1+10];
break;
case 2:
PORTA=0b00001100;
PORTB=p[tmp2];
break;
}
}

void main()
{
OSCCON = 0b0111000; // 内蔵OSC 8MHz
ADCS2 = 0; //AD変換クロック値設定
ADCS1 = 0;
ADCS0 = 1;
ADFM = 1; // AD変換結果は右詰めで格納
VCFG1 = 0; // 基準電圧はVddとVss
VCFG0 = 0;
ANSEL = 0b00000001; // RA0(AN0)はアナログ
TRISA = 0b00000001; // RA0(AN0)入力
TRISB = 0b00000000; // すべて出力
PORTA = 0b00011100;
PORTB = 0b00000000;

OPTION = 0x00;
TMR0 = 0x00; //TMR0は0からスタート
TMR0IE = 1; //TMR0割り込み許可
GIE = 1; //すべての割り込み許可

while (1)
{
tmp=adconv()*4.53;
tmp2=(tmp/100)%10;
tmp1=(tmp/10)%10;
tmp0=tmp%10;
__delay_ms(100); //100msの時間待ち
}
}

unsigned int adconv()
{
CHS2 = 0; //AD変換ポート設定 RA0(AN0)
CHS1 = 0;
CHS0 = 0;
ADON = 1; //AD変換ON
__delay_us(20); //アクィジション時間 20us
GODONE = 1; //AD変換開始
while(GODONE); //変換完了待ち
return (ADRESH<<8) + ADRESL;
}


 

| | コメント (0) | トラックバック (0)

2012年7月14日 (土)

PICのお勉強(31) C言語編 LM35DZで温度計

Lm35dz 温度センサLM35DZを使って温度計にしてみました。
 LM35DZは,0℃~100℃を0mV~1000mVでリニアに出力してくれますから,PICに直接つないで簡単に温度表示させることができます。
基準電圧はVddの5Vを使っていますから,分解能は約4.88mVです。A/D変換された値に4.88を掛ければ,温度センサが出力する電圧がmVの単位で得られますから,整数部分と小数部分に分けてLCDに送れば温度表示ができるわけです。こりゃ楽しいですなあhappy01
ソースはこれ→lesson31.c

/************************************
16F88 HI-TECH C v.9.83
温度計 LM35DZをRA0(AN0)に接続 LCD表示
************************************/

#define _LEGACY_HEADERS
#include "pic.h"
#include "stdlib.h"
#include "lcd.h"
#define _XTAL_FREQ 4000000
__CONFIG(DEBUGDIS & LVPDIS & BORDIS & MCLRDIS & PWRTEN & WDTDIS & INTIO);
__CONFIG(FCMDIS & IESODIS);

unsigned int adconv(),tmp,tmp1,tmp2;
char str[7],str1[7],str2[7];

void main()
{
OSCCON = 0b0110000; // 内蔵OSC 4MHz
ADCS2 = 0; //AD変換クロック値設定
ADCS1 = 0;
ADCS0 = 1;
ADFM = 1; // AD変換結果は右詰めで格納
VCFG1 = 0; // 基準電圧はVddとVss
VCFG0 = 0;
ANSEL = 0b00000001; // RA0(AN0)はアナログ
TRISA = 0b00000001; // RA0(AN0)入力
TRISB = 0b00000000; // すべて出力
PORTA = 0b00000000;
PORTB = 0b00000000;

lcd_init(); //SD1602の初期化
while (1)
{
tmp =adconv()*4.88;
tmp1=tmp/10;
tmp2=tmp-tmp1*10;
itoa(str1,tmp1,10);
itoa(str2,tmp2,10);

lcd_goto(0); //カーソルを0行目の先頭に移動する
lcd_puts("キオン ");
lcd_puts(str1);
lcd_puts(".");
lcd_puts(str2);
lcd_putch(0xDF);
lcd_puts("C");
__delay_ms(100); //100msの時間待ち
}
}

unsigned int adconv()
{
CHS2 = 0; //AD変換ポート設定 RA0(AN0)
CHS1 = 0;
CHS0 = 0;
ADON = 1; //AD変換ON
__delay_us(20); //アクィジション時間 20us
GODONE = 1; //AD変換開始
while(GODONE); //変換完了待ち
return (ADRESH<<8) + ADRESL;
}

| | コメント (0) | トラックバック (0)

2012年7月 9日 (月)

PICのお勉強(30) C言語編 AD変換の結果をLCDに表示する

Adsd16024bit_mode 前回の回路にLCDをつけて,A/D変換して得られた10bitの数値データを表示してみました。
 基準電圧が5Vだから1023が5Vにあたり,分解能は約5mVってことになりますね。そこで,データを5倍してmVの単位でLCDに表示しようと思います。要するにこれは電圧計ですな。
ソースはこれ→lesson30.c
 数値データをどうやったらLCDに表示できるのか悩みましたが,itoa(Integer to Asciiって意味?)という便利な関数があるんですな。コレで文字列にしといてLCDに送ればいいみたい。あ,あとlcd.cの「TRISA=0;」をコメントアウトしないといけません。「TRISA = 0b00000001;」としといてもいいけど。
 やってみると,ちゃんと表示されるじゃないですか。アタリマエかもしれないけど嬉しいですなあ。
Lesson30 LCDは,10msごとに表示を書き換えてるので,ちょっとチラチラするんだけど,これはなんか良い方法があるのかなあ? また調べときます(^^;)
 あと,LCDのコントラスト調整についてですが,SD1602の3ピン(VO)にダイオードを1本つけておくだけで,電源電圧が多少変わっても自動的に適正コントラストになるようです。VO端子は0.5V程度の電位にしておけば,適正コントラストになるらしいのですが,ダイオードを使えば約0.6Vになりますものね。ここに書いてありました。素晴らしいアイデアです。

/************************************
16F88 HI-TECH C v.9.83
RA0(AN0)の入力電圧をA/D変換してLCDに表示する
************************************/

#define _LEGACY_HEADERS
#include "pic.h"
#include "stdlib.h"
#include "lcd.h"
#define _XTAL_FREQ 4000000
__CONFIG(CCPRB3 & DEBUGDIS & LVPDIS & BOREN & MCLRDIS & PWRTEN & WDTDIS & INTIO);

unsigned int adconv();
unsigned int tmp;
unsigned int i;
char str[7];

void main()
{
OSCCON = 0b0110000; // 内蔵OSC 4MHz
ADCS2 = 0;     //AD変換クロック値設定
ADCS1 = 0;
ADCS0 = 1;
ADFM = 1; // AD変換結果は右詰めで格納
VCFG1 = 0; // 基準電圧はVddとVss
VCFG0 = 0;
ANSEL = 0b00000001; // RA0(AN0)はアナログ
TRISA = 0b00000001; // RA0(AN0)入力
TRISB = 0b00000000; // すべて出力
PORTA = 0b00000000;
PORTB = 0b00000000;

 lcd_init(); //SD1602の初期化
while (1)
{
tmp = adconv()*5;
itoa(str,tmp,10);

lcd_clear(); //表示クリア
lcd_goto(0); //カーソルを0行目の先頭に移動する
lcd_puts(str);
lcd_puts("mV");
__delay_ms(10); //10msの時間待ち

}
}

unsigned int adconv()
{
CHS2 = 0; //AD変換ポート設定 RA0(AN0)
CHS1 = 0;
CHS0 = 0;
ADON = 1; //AD変換ON
__delay_us(20); //アクイジション時間 20us
GODONE = 1; //AD変換開始
while(GODONE); //変換完了待ち
return (ADRESH<<8) + ADRESL;
}


| | コメント (1) | トラックバック (0)

より以前の記事一覧