2013年11月15日金曜日

Atmega8-16PU + USB-UART変換モジュールでUSBマトリクスLED表示器

前回でマトリクスLEDのダイナミック制御ができるようになったので、さらに一歩前進して

USART(シリアル通信)で描画パターンを指定できるようにする。

前回の回路に加えて、以前買っておいたaitendoのUSB-UART変換モジュールを使用する。





回路的には前回の回路にAtmega8のRXとTXを変換モジュールに接続するだけ。

変換モジュールに3.3V電源とGNDがついているのでそれを利用することでUSBバスパワー駆動となる。

信号線と電源が一緒にできるなんてUSB最高ですね。


で、回路は簡単だったのだけどソフトはかなり手こずった。

最初、橋本商会さんのページを参考にしたんだけど、avr-gccなのか、チップ自体の仕様変更なのか割り込みのコードが変わっててビルドエラーになって戸惑う等、落とし穴盛りだくさんな感じだった。

最終的な参考サイトは以下

Interrupt Driven USART in AVR-GCC(PDF)
http://www.fourwalledcubicle.com/AVRArticles.php

http://homepage3.nifty.com/rio_i/lab/avr/03usart.html
http://homepage3.nifty.com/rio_i/lab/avr/03usart.html

ソースコード
----
/*
atmega8 16pu
matrix led(1088bgy) controller
ISP
PC6 RESET
PB5 SCK
PB4 MISO
PB3 MOSI
USART
PD0 RXD
PD1 TXD
LED
ROW PC0,PC1,PC2,PC3,PC4,PC5,PB0,PB1
COL PB6,PB7,PD2,PD3,PD4,PD5,PD6,PD7
*/
#define F_CPU 1000000UL // Clock Speed
#define BAUD 9600
#define MYUBRR (((F_CPU / (BAUD * 16UL))) - 1)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
/* DDRC |= (1 << PC0); */
#define DSET(p,n) (DDR##p|=(1<<P##p##n))
/* PORTC |= (1 << PC0); */
#define PSET(p,n,d) \
if ((d)) { \
(PORT##p|=(1<<P##p##n));\
} else { \
(PORT##p&=~(1<<P##p##n));\
}
volatile unsigned char matrix[8] = {
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111
};
volatile unsigned char mindex;
void
USART_Init(unsigned int ubrr)
{
/* Set baud rate */
UBRRH = (ubrr>>8);
UBRRL = ubrr;
/* Enable receiver and transmitter */
UCSRB = (1 << RXEN) | (1 << RXCIE);
/* Set frame format: 8 data bits, 1 stop bit */
UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1);
/* all interrupt allow */
sei();
}
void
init_port()
{
// port c output setting
DSET(C,0);
DSET(C,1);
DSET(C,2);
DSET(C,3);
DSET(C,4);
DSET(C,5);
// port b output setting
DSET(B,0);
DSET(B,1);
DSET(B,6);
DSET(B,7);
// port d output setting
DSET(D,2);
DSET(D,3);
DSET(D,4);
DSET(D,5);
DSET(D,6);
DSET(D,7);
}
void
row(int i,int d)
{
switch(i) {
case 0:PSET(C,0,d);break;
case 1:PSET(C,1,d);break;
case 2:PSET(C,2,d);break;
case 3:PSET(C,3,d);break;
case 4:PSET(C,4,d);break;
case 5:PSET(C,5,d);break;
case 6:PSET(B,0,d);break;
case 7:PSET(B,1,d);break;
}
}
void
col(int i,int d)
{
switch(i) {
case 0:PSET(B,6,d);break;
case 1:PSET(B,7,d);break;
case 2:PSET(D,2,d);break;
case 3:PSET(D,3,d);break;
case 4:PSET(D,4,d);break;
case 5:PSET(D,5,d);break;
case 6:PSET(D,6,d);break;
case 7:PSET(D,7,d);break;
}
}
void
allcut()
{
// col
PSET(B,6,0);
PSET(B,7,0);
PSET(D,2,0);
PSET(D,3,0);
PSET(D,4,0);
PSET(D,5,0);
PSET(D,6,0);
PSET(D,7,0);
// row
PSET(C,0,1);
PSET(C,1,1);
PSET(C,2,1);
PSET(C,3,1);
PSET(C,4,1);
PSET(C,5,1);
PSET(B,0,1);
PSET(B,1,1);
}
#define DELAY 800
int
main(void)
{
int i,j;
init_port();
USART_Init(MYUBRR);
mindex = 0;
while (1) {
for(i=0;i<8;i++) {
allcut();
for(j=0;j<8;j++) {
col(j,(matrix[i]&1<<j)>>j);
if (i==j) {
row(j,0);
}
}
_delay_us(DELAY);
}
}
return 0;
}
ISR(USART_RXC_vect)
{
matrix[mindex] = UDR;
if (mindex >= 7) {
mindex = 0;
} else {
mindex++;
}
}
view raw usart.c hosted with ❤ by GitHub
# encoding:utf-8
require 'serialport'
$serial_port = '/dev/ttyUSB1'
$serial_baudrate = 9600
$serial_databit = 8
$serial_stopbit = 1
$serial_paritycheck = 0
sp = SerialPort.new($serial_port, $serial_baudrate, $serial_databit, $serial_stopbit, $serial_paritycheck)
sp.read_timeout=1000
c = 0x00
256.times do
sp.putc c
c+=1
sleep 1
end
sp.close
view raw usart.rb hosted with ❤ by GitHub
# encoding:utf-8
require 'serialport'
$serial_port = '/dev/ttyUSB1'
$serial_baudrate = 9600
$serial_databit = 8
$serial_stopbit = 1
$serial_paritycheck = 0
sp = SerialPort.new($serial_port, $serial_baudrate, $serial_databit, $serial_stopbit, $serial_paritycheck)
sp.read_timeout=1000
sleep 1
c = 0b01010101
loop {
8.times do
sp.putc c
c = ~c
end
sleep(0.3)
8.times do
c = ~c
sp.putc c
end
sleep(0.3)
}
sp.close
view raw usart2.rb hosted with ❤ by GitHub
----

解説

usart.c

  • Atmega8-16PU用プログラム
  • シリアル通信はRX(受信)のみ
  • 1バイト受信したら割り込み処理で1行分のパターン(1バイト)を更新
  • 1バイト受信する毎に更新対象の行を1行ずらす(8バイトで全行更新)
usart.rb
  • テスト用Rubyスクリプト
  • 0x00から0xFFまで1秒ごとに1バイトずつ送信
ハマりポイント
  • シグナルハンドラがSIGNAL(SIG_UART_RECV)からISR(USART_RXC_vect)に変わってた
  • プロセッサの動作周波数はFOSCじゃなくてF_CPUだった
  • UCSRBのRXCIEを立てること(割り込み指定)
  • UCSRCのUSBSを間違って立てていてストップビット2になってた
  • パターンの変数matrixにvolatile指定が必要だった
  • F_CPU 8MHzだと上手く動かなかった -> 1MHzに
最後に動作風景


うし。ユニバーサル基板に実装してUSBマトリクスLED表示器を作るど。

0 件のコメント:

amazonアソシエイト