ATMELのAT-Tiny26,ATmega,R8Cなどのワンチップマイコン,C言語,JAVAなどのプログラミング言語の入門のためのページです.サンプルプログラムを中心に紹介します.他にもLinixや数学ソフトなどの紹介も行います.

このブログを検索

あなたは 番目のお客様です.

2008年9月16日火曜日

Tiny2313を使ってシリアル通信とEEP-ROMリーダ









Tiny2313を使ってシリアル通信でPCと接続するサンプルプログラムです.
PC側からaを入力すればPB0に接続したLEDが点灯し,
bを入力すればLEDが消灯し,
c-zを入力すればPC側に大文字を返します.
Tiny2313は8MHzの外部発振で,分周なしの設定にしておきます.
PC側の設定は,ボーレート19200,データ8ビット,
パリティnone,ストップ1bitフロー制御noneにしておきます.
/*シリアル通信でPCとTiny2313を接続する
comtn2313b.c(通信の初期設定をmainに入れた)
Ext8MHz,分周なし,ビットレート:19200,U2X=0
a:LED on b:LED off c-z:大文字を返す
*/

#include <avr/io.h>

void Utx(unsigned char data) //マイコンからデータを送信する
{
while ( !(UCSRA & (1<<UDRE)) );
UDR = data;
}

unsigned char Urx(void) //マイコンがデータを受信する
{
while ( !(UCSRA & (1<<RXC)) );
return UDR;
}

int main(void){
unsigned char dat;
unsigned int baud;
baud=8000000/16/19200-1;//ボーレートの計算
UBRRH = (unsigned char)(baud>>8);//ボーレート上位
UBRRL = (unsigned char)baud; //ボーレート下位
UCSRC = (1<<USBS)|(3<<UCSZ0);
UCSRB = (1<<RXEN)|(1<<TXEN);//送受信可

DDRB=0B00000001; //PD0(Output)
while(1){
dat = Urx();
if(dat=='a')PORTB=0B00000001; //PD0 H(LED:on)
if(dat=='b')PORTB=0B00000000; //PD0 L(LED:off)
if(dat>'b'){ //c-zは大文字を返す
dat=dat-'a'+'A';
Utx(dat);
Utx(0x0a); //LF
Utx(0x0d); //CR
}
}//while(1)
}


続いて以下は,Tiny2313とEEP-ROM(ATMEL24C256)をつないだROMリーダです.
パソコンで数値,sと入力するとEEP-ROMの先頭からn個のデータを
RS-232Cを通してPCに出力します.
/*
EEP-ROM リーダーTiny2313(ExtOsc8MHz,クロックを8分周しない)
ATMEL24C256の場合8ビット×32K,32K=2^15=32768
次のように最初のアドレス:データを続けて表示する
0000:000102030405060708090A0B0C0D0E0F
0010:101112131415161718191AFFFFFFFFFF
0020:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
ボーレートは19200
マイコンとADM3202,24C256の接続は以下の通り
(Tiny2313)RXD--(ADM3202)R1OUT
(Tiny2313)TXD--(ADM3202)R1IN
(Tiny2313)PB0--(24C256)SCL(1kΩでプルアップ)
(Tiny2313)PB1--(24C256)SDA(1kΩでプルアップ)
*/

#include <avr/io.h>

//マイクロ秒単位の待ち(t<256)
void delay(int8_t t){
TCCR0B=0B00000010; //タイマカウンタ0の分周をセットCK/8
TCNT0=0;
while(TCNT0<t){}
}

void start(void){
PORTB|= 1<<1;// set PB1
PORTB|= 1<<0; // set CLK
delay(5);
PORTB&=~(1<<1); // clear PB1
PORTB&=~(1<<0); // clear CLK
delay(5);
}
void stop(void){
PORTB&=~(1<<1); // clear PB1
PORTB|= 1<<0; // set CLK
delay(5);
PORTB|= 1<<1;// set PB1
PORTB&=~(1<<0); // clear CLK
delay(5);
}
void Hclk(void){//SDAがhighで1クロック
PORTB|= 1<<1;// set PB1
PORTB|= 1<<0; // set CLK
delay(5);
PORTB&=~(1<<0); // clear CLK
delay(5);
}
void Lclk(void){//SDAがlowで1クロック
PORTB&=~(1<<1); // clear PB1
PORTB|= 1<<0; // set CLK
delay(5);
PORTB&=~(1<<0); // clear CLK
delay(5);
}

//データ読み込み
uint8_t read(uint16_t add){
uint8_t i;
uint16_t k;
start();
for(k=0B100000000;k>0;k=k>>1)if(k & 0B101000000)Hclk();
else Lclk();
i=add/256; //上位アドレス
for(k=0B10000000;k>0;k=k>>1)if(k & i)Hclk();
else Lclk();
Lclk();//ACK

i=add%256; //下位アドレス
for(k=0B10000000;k>0;k=k>>1)if(k & i)Hclk();
else Lclk();
Lclk();//ACK
start();
for(k=0B100000000;k>0;k=k>>1)if(k & 0B101000010)Hclk();
else Lclk();
DDRB&=~(1<<1); //PB1を入力に変更
i=0;
for(k=0B10000000;k>0;k=k>>1){
PORTB|= 1<<0; // set CLK
delay(5);
if(PINB & (1<<1))i+=k;
PORTB&=~(1<<0); // clear CLK
delay(5);
}
DDRB|= 1<<1; //PB1を出力に変更
Hclk();//NO ACK
stop();//Stop
return i;
}

void Utx(unsigned char data) //マイコンからデータを送信する
{
while ( !(UCSRA & (1<<UDRE)) );
UDR = data;
}
unsigned char Urx(void) //マイコンがデータを受信する
{
while ( !(UCSRA & (1<<RXC)) );
return UDR;
}

int main(void)
{
uint8_t x,y,dat;
uint16_t i,j,k=0,baud=25; //ボーレートの計算=8000000/16/19200-1
UBRRH = (unsigned char)(baud>>8);//ボーレート上位
UBRRL = (unsigned char)baud; //ボーレート下位
UCSRC = (1<<USBS)|(3<<UCSZ0);
UCSRB = (1<<RXEN)|(1<<TXEN);//送受信可

DDRB=0B00000011; //PB0,PB1:OUT
TIMSK|= 1<<TOIE0; //タイマカウンタ0のオーバーフロー割り込みを許可する
//sei(); //All Int Enable 割り込みを可能にする

while((dat = Urx())!='s')k=k*10+dat-'0';//'s'が入力されるまで待つ

for(i=0;i<k/16;i++){
//最初のアドレス(i*16)を表示
//16進のiと0を表示するのはi*16を表示するのと同じである
y=i/256;
if(y>9)Utx('A'+y-10);
else Utx('0'+y);
y=(i%256)/16;
if(y>9)Utx('A'+y-10);
else Utx('0'+y);
y=i%16;
if(y>9)Utx('A'+y-10);
else Utx('0'+y);
Utx('0');
Utx(':');
for(j=0;j<16;j++){

x=read(i*16+j); //Read EEP
y=x/16;
if(y>9)Utx('A'+y-10);
else Utx('0'+y);
y=x%16;
if(y>9)Utx('A'+y-10);
else Utx('0'+y);
}//for i
Utx(0x0a); //LF
Utx(0x0d); //CR
}//for i
while(1){}
}

2008年9月15日月曜日

AVR入門

AVRDRAGONを使う
AVRマイコンの書き込みは,AVRISPmkIIが入門用として使いやすいです.
AVRDRAGONを使ってみました.AVRDRAGONはボードのみです.AVRISPmkIIのようにUSBケーブルや8ピンケーブル,ソフトのCDが付いていません.ただAVRISPmkIIを使ったことがある人ならば,特に問題なく使えると思います.
AVRstudioをインストールしていれば,新しくインストールするものはありません.
AVRDRAGONを接続すれば,ドライバのインストールが始まります.
mkIIと同様に6ピンのISPとターゲットのマイコンを接続すれば,ISPプログラミングが可能です.
AVRDRAGONはUSB電源(5V)のピンを持っています.このVCCをマイコンに供給すれば,マイコン側で電源は不要です.
一方で過去に作ったマイコンのプログラマターゲットを使いたい場合,両者の電源がバッティングします.私は3V電源のマイコンのプログラマターゲットを使っていました.
そこでAVRDRAGONのVCCとISP6ピンのVTGを100Ωの抵抗で結びました.こうすれば,電源無しのターゲットでも3V電源のターゲットでも同じように使えます.
写真の左が,AVRDRAGONの裏側,右上がtiny2313のターゲット,右下がmega88のターゲットです.










AVRのアセンブラの比較
よく使うAT90S1200,AT90S2313,ATTINY2313,ATTINY26で3個のLEDを点滅させるアセンブラプログラムの比較を行いました.
定義ファイルはそれぞれ,"1200def.inc","2313def.inc","tn2313def.inc","tn26def.inc"です.それぞれ割り込みベクタの数が違うのでRETIの数が異なります.
AT90S1200にはスタックポインタの記述がありません.AT90S2313とATTINY2313のスタックポインタ名はSPLで,ATTINY26のスタックポインタ名はSPです.
またATTINY2313にはクロックの分周機能が着いていて,これがセットさたままだと速度が8分の1になるので気をつけましょう.
以下AT90S1200,AT90S2313,ATTINY2313,ATTINY26のソースプログラムです.

;90S1200
.include "1200def.inc"
.def CNT1 =R17
.def CNT2 =R18
.def CNT3 =R19
RJMP RESET
RETI
RETI
RETI
RESET: LDI R16,0B11111111
OUT DDRD,R16
MAIN:
LDI R16,0B00001000
OUT PORTD,R16
RCALL TIME
LDI R16,0B00010000
OUT PORTD,R16
RCALL TIME
LDI R16,0B00100000
OUT PORTD,R16
RCALL TIME
RJMP MAIN
TIME:
LDI CNT1,10
LOOP1:
LDI CNT2,255
LOOP2:
LDI CNT3,255
LOOP3:
NOP
NOP
DEC CNT3
BRNE LOOP3
DEC CNT2
BRNE LOOP2
DEC CNT1
BRNE LOOP1
RET


;90S2313 led2313.asm
.include "2313def.inc"
.def CNT1 =R17
.def CNT2 =R18
.def CNT3 =R19
RJMP RESET
RETI ;1
RETI
RETI
RETI
RETI
RETI
RETI
RETI
RETI ;$9
RETI ;$A
RESET: LDI R16,LOW(RAMEND)
OUT SPL,R16
LDI R16,0B11111111
OUT DDRD,R16
MAIN:
LDI R16,0B00001000
OUT PORTD,R16
RCALL TIME
LDI R16,0B00010000
OUT PORTD,R16
RCALL TIME
LDI R16,0B00100000
OUT PORTD,R16
RCALL TIME
RJMP MAIN
TIME:
LDI CNT1,10
LOOP1:
LDI CNT2,255
LOOP2:
LDI CNT3,255
LOOP3:
NOP
NOP
DEC CNT3
BRNE LOOP3
DEC CNT2
BRNE LOOP2
DEC CNT1
BRNE LOOP1
RET


;Tiny2313 ledtn2313.asm
;システム クロック前置分周器に注意
.include "tn2313def.inc"
.def CNT1 =R17
.def CNT2 =R18
.def CNT3 =R19
RJMP RESET
RETI ;1
RETI
RETI
RETI
RETI
RETI
RETI
RETI
RETI ;$9
RETI ;$A
RETI
RETI
RETI
RETI
RETI
RETI ;$10
RETI ;$11
RETI ;$12
RESET: LDI R16,LOW(RAMEND)
OUT SPL,R16
LDI R16,0B11111111
OUT DDRD,R16
MAIN:
LDI R16,0B00001000
OUT PORTD,R16
RCALL TIME
LDI R16,0B00010000
OUT PORTD,R16
RCALL TIME
LDI R16,0B00100000
OUT PORTD,R16
RCALL TIME
RJMP MAIN
TIME:
LDI CNT1,10
LOOP1:
LDI CNT2,255
LOOP2:
LDI CNT3,255
LOOP3:
NOP
NOP
DEC CNT3
BRNE LOOP3
DEC CNT2
BRNE LOOP2
DEC CNT1
BRNE LOOP1
RET


;Tiny26 ledtn26.asm
;スタックポインタ名はSPLではなくSP
;PB0,1,2にLEDを接続した
;PIN7(RESET)PIN15(AVCC)PIN16(GND)を開放しても動く
.include "tn26def.inc"
.def CNT1 =R17
.def CNT2 =R18
.def CNT3 =R19
RJMP RESET
RETI ;1
RETI
RETI
RETI
RETI
RETI
RETI
RETI
RETI ;$9
RETI ;$A
RETI ;$B
RESET: LDI R16,LOW(RAMEND)
OUT SP,R16
LDI R16,0B00000111
OUT DDRB,R16
MAIN:
LDI R16,0B00000001
OUT PORTB,R16
RCALL TIME
LDI R16,0B00000010
OUT PORTB,R16
RCALL TIME
LDI R16,0B00000100
OUT PORTB,R16
RCALL TIME
RJMP MAIN
TIME:
LDI CNT1,10
LOOP1:
LDI CNT2,255
LOOP2:
LDI CNT3,255
LOOP3:
NOP
NOP
DEC CNT3
BRNE LOOP3
DEC CNT2
BRNE LOOP2
DEC CNT1
BRNE LOOP1
RET

2008年9月12日金曜日

マイコンと2進数

マイコンの中での数の扱い(2進数)に関するメモです
コンピュータ内部では数値はすべて2進数が基本となっている.電流が流れる状態を1(ON),電流が流れない状態を0(OFF)としている.1つの電流の状態を1ビット(byte)と呼ぶ.8ビットを1つのまとまりとして1バイト(byte)とする.

2進数を4桁ずつまとめると16進数になる.2進数をそのまま書くと長くなるので通常は16進数で表すことが多い.
0B0000=0X0
0B0001=0X1
0B0010=0X2
0B0011=0X3
.
.
0B1110=0XE
0B1111=0XF
先頭に0Bを付ける数は,2進数を意味する.16進数の場合,先頭に0Xや0$を付ける.

例題
次の2進数を16進数に変換してみよう.
0B01001111(16進数 ) 0B11001001(16進数 )

次の16進数の計算をやってみよう.10進数にも変換してみよう.
0X1E
+0XAA
-------


符号なしと符号ありの2進数
2進数には符号なしと符号ありの2種類の表記方法がある.自分が扱っている数が,符号なしなのか符号ありなのかを注意する必要がある.

符号なし2進数
符号なし2進数では,8ビットで0から255まで(256通り)の数を表現できる.

2進数 00000000(10進数で0)
00000001(1)
00000010 (2)
00000011(3)
...途中略...
11111111( 255)

次の2進数の計算をやってみよう.
01001011
+10011001
---------



10011001
-01101011
---------


符号あり2進数
符号あり2進数では,8ビットで-128から127まで(256通り)の数を表現できる.

2進数 10000000(10進数で-128)
10000001 (-127)
10000010(-126)
10000011 (-125)
...途中略...
11111111(-1)
00000000(0)
00000001(1)
00000010(2)
00000011(3)
...途中略...
01111111(127)

次の符号あり2進数の計算をやってみよう.
01001011
+10011001
---------


C言語では,文字型変数charは1バイトの符号あり2進数である.従って次の処理で変数はマイナスの値(-128)となる.
char i=127;
i++;