(Tiny26でAD変換の結果を液晶に表示する)
以下はTiny26でAD変換の結果を液晶SC1602BSで表示するサンプルプログラムです.
内部発振または外部発振の8MHzに対応しています.
AD変換の入力ピンはADC9です.
AD変換の精度を確保するためにはADPS0,ADPS1,ADPS2で
A/D変換クロックを50-200kHzに設定する必要があります.
;DB7<->PA7 DB6<->PA6
;DB5<->PA5 DB4<->PA4
;DB3<->Open DB2<->Open
;DB1<->Open DB0<->Open
;E<->PA2 R/W<->GND
;RS<->PA0 Vo<->GND
;Vss<->GND Vdd<->5V
以下がソースプログラム
プログラムを修正すれば,温度センサLM35による温度表示
が可能です
/*
Tiny26でAD変換を行い液晶SC1602BSに表示する
TCNT0を使い時間をコントロールする
AD変換の基準電圧は2.56V
AD変換の精度を確保するためにはADPS0-2で
A/D変換クロックを50-200kHzに設定する必要あり
CK=8MHzのときCK/64=125kHz
Int.RC Osc. 8MHz:Start-up time:6CK+64ms
Tiny26--SC1602BSのピン接続
PA0--RS
PA1
PA2--E
PA3
GND
AVCC
PA4--DB4
PA5--DB5
PA6--DB6
PA7--DB7
GND--R/W,Vo,Vss
5V--Vdd
*/
#include <avr/io.h>
//マイクロ秒単位の待ち
void delay(uint8_t t){
TCCR0=0B00000010;//clk/8 (8分周)
TCNT0=255-t;
TIFR |= 1<<TOV0;//TOV0クリア
while(!(TIFR & (1<<TOV0))){}//カウンタがオーバーフローするまで待つ
}
void en(void){
PORTA|= 1<<2;
delay(20);
PORTA&=~(1<<2);
delay(20);
}
void cmnd(uint8_t i){
PORTA=i&(0B11110000);
en();
PORTA=(i<<4)&(0B11110000);//i<<4は4ビット左シフト &はビット間のAND
en();
delay(40);
}
//データの書き込み
void dat(uint8_t i){
PORTA=i&(0B11110000);
PORTA|= 1<<0; //RS:High
en();
PORTA=(i<<4)&(0B11110000);
PORTA|= 1<<0; //RS:High
en();
delay(40);
PORTA&=~(1<<0); //RS clear
}
int main(void)
{
uint8_t ad;
uint16_t i;
DDRA=0xFF; //PA全て出力
DDRB=0X00; //PB全て入力
ADMUX=0B10101001; //INTENAL V REF. LEFT ADJUST, ADC9
ADCSR=0B10000110; //SET ADCSR CK/64
for(i=0;i<80;i++)delay(250); //Wait 20ms
PORTA=0B00110000;
en();
for(i=0;i<20;i++)delay(250); //Wait 5ms
en();
delay(100); //Wait 100Us
en();
delay(50); //Wait 50Us
PORTA=0B00100000; //Function set
en();
delay(50); //Wait 50Us
cmnd(0B00101100); //N=1:2lines F=1:10dots
cmnd(0B00001100); //Display On Off Control
cmnd(0B00000110); //Entry Mode Increment
while(1){
cmnd(0B00000001); //Clear LCD
for(i=0;i<8;i++)delay(250); //Wait 2ms
ADCSR|= 1<<ADSC; //AD start
while(!(ADCSR & (1<<ADIF))){}//ADCSRのビット4(ADIF)が1になるまで待つ
ad=ADCH;
dat(0X30+ad/100); //0X30='0'
ad%=100;
dat(0X30+ad/10);
//dat(0X2E); //dot
ad%=10;
dat(0X30+ad);
//dat(0X20); //SPACE
//dat(0X56); //V
for(i=0;i<4000;i++)delay(250); //Wait 1000ms
}//while(1)
}
以下はアセンブラのプログラムです
;adlc.asm AD conversion +LCDの改良版 2006-9-20
;ADC9(PB6)の電圧をAD変換し10進数に変換し液晶で表示する
;ATtiny26L (Internal Osc 1MHz)
;INTENAL V REF. LEFT ADJUST, ADC9(PB6)
;「R/W RS DB0-7」の信号線にはプルアップ抵抗が入っているので
;DB0-3はGNDにつながずオープン
;マイコンからは書き込みだけで読み込みが無ければ,R/WピンをGNDに
;RS=1:Instruction RS=0:DATA
;Vo (Contrast ADJ)は,電圧がGNDに近づくほど濃くなる.
;LCDのピンは上部左上から
;14:DB7 13:DB6
;12:DB5 11:DB4
;10:DB3 9:DB2
;8:DB1 7:DB0
;6:E(Enable Signal) 5:R/W (Read/Write)
;4:RS(Register Select) 3:Vo (Contrast ADJ)
;2:Vss(0V) 1:Vdd(5V)
;DB7<->PA7 DB6<->PA6
;DB5<->PA5 DB4<->PA4
;DB3<->Open DB2<->Open
;DB1<->Open DB0<->Open
;E<->PA2 R/W<->GND
;RS<->PA0 Vo<->GND
;Vss<->GND Vdd<->5V
.INCLUDE "tn26def.inc"
.equ en =2 ;PB2
.def TEMP =R16
.def data =R17 ;DATA
.def CT1 =R18
.def CT2 =R19
.def CT3 =R20
.def BIN0 =R21
.def DEC0 =R22
.def DEC1 =R23
.def DEC2 =R24
.def DECI =R25
RJMP RESET
RETI
RETI
RETI
RETI
RETI
RETI
RETI
RETI
RETI
RETI
RETI
RESET: LDI TEMP,RAMEND
out SP,TEMP
LDI TEMP,0B11110101
out DDRA,TEMP ;PA7-4,PA2,PA0 OUTPUT
;***************** LCD initialize ******************************************
RCALL TM10 ;WAIT ABOUT 10ms
RCALL TM10
RCALL TM10
RCALL TM10
LDI data,0B00110000 ;Function Set DL=1:8bit
OUT PORTA,data
sbi PORTA,en
cbi PORTA,en
RCALL TM10
sbi PORTA,en
cbi PORTA,en
RCALL TM10
sbi PORTA,en
cbi PORTA,en
RCALL TM10
RCALL TM10
LDI data,0B00100000 ;Function Set DL=0:4bit
OUT PORTA,data
sbi PORTA,en
cbi PORTA,en
;ここから4ビットモード
LDI data,0B00101100 ;N=1:2lines F=1:10dots
RCALL cmnd
LDI data,0B00000001 ;Clear Dsplay
RCALL cmnd
LDI data,0B00001100 ;Display On Off Control
RCALL cmnd
LDI data,0B00000110 ;Entry Mode Increment
RCALL cmnd
;*****************AD Initialize**********************************************
LDI TEMP,0X00
OUT DDRB,TEMP ;set PORTB INPUT
LDI TEMP,0B10101001 ;INTENAL V REF. LEFT ADJUST, ADC9
OUT ADMUX,TEMP
LDI TEMP,0B10000000 ;SET ADCSR
OUT ADCSR,TEMP
main: LDI TEMP,0B11000000 ;START CONVERSION
OUT ADCSR,TEMP
ADLP: SBIS ADCSR,4
RJMP ADLP
IN DECI,ADCL ;小数点以下の値
IN BIN0,ADCH
ldi data,0B00000001 ;clear LCD
rcall cmnd ;out command
RCALL B2D ;2進数を10進数に変換 BIN0->DEC2,DEC1,DEC0
LDI TEMP,0X30 ;0X30='0'
ADD DEC2,TEMP
ADD DEC1,TEMP
ADD DEC0,TEMP
MOV data,DEC2
RCALL write
MOV data,DEC1
RCALL write
MOV data,DEC0
RCALL write
;************ Display Dicimal Fraction
LDI data,0X2E ;"."
RCALL write
;DECI: 11000000->75 10000000->50 01000000->25 00000000->00
LDI BIN0,75 ;BIN0=75
SBRS DECI,7 ;DECIのビット7が1ならスキップ
SUBI BIN0,50 ;BIN0-=50
SBRS DECI,6 ;DECIのビット6が1ならスキップ
SUBI BIN0,25 ;BIN0-=25
RCALL B2D ;2進数を10進数に変換 BIN0->DEC2,DEC1,DEC0
LDI TEMP,0X30 ;0X30='0'
ADD DEC1,TEMP
ADD DEC0,TEMP
MOV data,DEC1 ;小数点以下一位
RCALL write
MOV data,DEC0 ;小数点以下二位
RCALL write
;
RCALL TM ;about 0.5s
rjmp main
;*** command and write to LCD *** rs PA0 en PA2
cmnd: MOV TEMP,data ;DATA をTEMPにコピー
SWAP TEMP ;SWAP:上位,下位ビットを交換
CBR data,0B00001111 ;PA0-3->0 RS=0 INSTRUCTION
CBR TEMP,0B00001111
OUT PORTA,data ;上位ビットを書き出し
sbi PORTA,en
cbi PORTA,en
OUT PORTA,TEMP ;下位ビットを書き出し
sbi PORTA,en
cbi PORTA,en
RCALL TM10
RET
write: MOV TEMP,data ;DATA をTEMPにコピー
SWAP TEMP ;SWAP:上位,下位ビットを交換
CBR data,0B00001111 ;RS=0 INSTRUCTION
CBR TEMP,0B00001111
SBR data,0B00000001 ;PA0-3->0 RS=1 DATA
SBR TEMP,0B00000001
OUT PORTA,data ;上位ビットを書き出し
sbi PORTA,en
cbi PORTA,en
OUT PORTA,TEMP ;下位ビットを書き出し
sbi PORTA,en
cbi PORTA,en
RCALL TM10
RET
;******************* timer *********************************************
TM10: LDI CT2,100 ;ABOUT10ms
LP1: LDI CT1,100
LP2: nop
dec CT1
brne LP2
dec CT2
brne LP1
RET
;******************** timer *******************************************
TM: LDI CT3,10
LP: RCALL TM10
dec CT3
brne LP
RCALL TM10
RET
;******************** BINARY TO DECIMAL****************************
B2D: LDI DEC2,0 ;2進数BIN0を10進数DEC2-0に変換
LDI DEC1,0
LDI DEC0,0
MOV CT1,BIN0
D2: LDI TEMP,100 ;100ずつ引いて,DEC2++
CP CT1,TEMP ;CT1とTEMPを比較
BRCS D1 ;キャリーがセット(CT1-TEMP<0)ならD1へジャンプ
SUBI CT1,100
INC DEC2
RJMP D2
D1: LDI TEMP,10 ;10ずつ引いて,DEC1++
CP CT1,TEMP
BRCS D0
SUBI CT1,10
INC DEC1
RJMP D1
D0: LDI TEMP,1 ;1ずつ引いて,DEC0++
CP CT1,TEMP
BRCS DD
SUBI CT1,1
INC DEC0
RJMP D0
DD: RET
(Tiny861でAD変換の結果を液晶に表示する)
以下はTiny861でAD変換の結果を液晶で表示するサンプルプログラムです.
内部発振または外部発振の8MHzに対応しています.
SC1602BS,DMC16117Aで動作確認しています.
AD変換の入力ピンはADC9です.
内部発振Int.RC Osc. 8MHz:Start-up time:6CK+64ms
Tiny861--液晶のピン接続
PA0--DB4
PA1--DB5
PA2--DB6
PA3--DB7
GND
AVCC
PA4--RS
PA5--E
PA6
PA7
GND--R/W,Vo,Vss
VCC--Vdd
PB6--AD入力
DB,RS,Eのピンを変えたときには,#defineを書き換えてください.
#include <avr/io.h>
#define RS 4
#define EN 5
#define DB4 0
#define DB5 1
#define DB6 2
#define DB7 3
//マイクロ秒単位の待ち
void delay(uint8_t t){
TCCR0B=0B00000010;//clk/8
TCNT0L=255-t;
TIFR |= 1<<TOV0;//TOV0クリア
//カウンタがオーバーフローするまで待つ
while(!(TIFR & (1<<TOV0))){}
}
void en(void){
PORTA|= 1<<EN;
delay(20);
PORTA&=~(1<<EN);
delay(20);
}
void cmnd(uint8_t i){
PORTA=(i>>4)&0B00001111;//上位データ
en();
PORTA=i&(0B00001111);//下位データ
en();
delay(40);
}
//データの書き込み
void dat(uint8_t i){
PORTA=(i>>4)&0B00001111;//上位データ
PORTA|= 1<<RS; //RS
en();
PORTA=i&(0B00001111);//下位データ
PORTA|= 1<<RS; //RS
en();
delay(40);
PORTA&=~(1<<RS); //RS clear
}
int main(void)
{
uint8_t ad;
uint16_t i;
DDRA=0B11111111; //PA全て出力
DDRB=0X00; //PB全て入力
ADMUX=0B10101001; //VREF2.56V LEFT ADJUST, ADC9
ADCSRA=0B10000110; //SET ADCSR CK/64
ADCSRB=0B00010000; //REFS2:HIGH VREF=2.56V
for(i=0;i<80;i++)delay(250); //Wait 20ms
PORTA=(1<<DB4)|(1<<DB5); //0011
en();
for(i=0;i<20;i++)delay(250); //Wait 5ms
en();
delay(100); //Wait 100Us
en();
delay(50); //Wait 50Us
PORTA=(1<<DB5); //0010
en();
delay(50); //Wait 50Us
cmnd(0B00101100); //N=1:2lines,F=1:10dots
cmnd(0B00001100); //Display On Off Control
cmnd(0B00000110); //Entry Mode Increment
while(1){
cmnd(0B00000001); //Clear LCD
for(i=0;i<8;i++)delay(250); //Wait 2ms
ADCSRA|= 1<<ADSC; //AD start
while(!(ADCSRA & (1<<ADIF))){}//AD変換を待つ
//10進に変換して表示
ad=ADCH;
dat(0X30+ad/100); //0X30='0'
dat('.'); //dot
ad%=100;
dat(0X30+ad/10);
ad%=10;
dat(0X30+ad);
dat(' '); //SPACE
dat('V'); //V
for(i=0;i<4000;i++)delay(250); //Wait 1000ms
}//while(1)
}