2010年
7月
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

セットアップ日記


2010年07月18日 RS232Cモニター

_ AVRでRS232Cのmonitor

PS2のマウスをAVRで扱おうと計画しているが、その前段階として、RS232Cのモニターを作ってみた。具体的には、PCからRS232Cで送った数字を、液晶で表示するというものだ。PCからのデータは次のようなスクリプトでrubyから送信できる。
s=open("/dev/ttyS0","r+")
system("stty raw -echo -crtscts 9600 cs8 -parenb cstopb </dev/ttyS0")
# 9600bps 8bit, 2 stop bit, no parity
loop{
  i=rand(256)
  puts '%02x'%i
  s.write(i.chr)
  s.flush
  sleep 1
}
この信号をMAX232でTTLレベルに変換して、それをtiny2313のUSARTの機能を使って受信する。あとは液晶表示ルーチンを利用して表示するだけだ。あまりきれいではないけれど、そのソースはこんな感じ。
#include 
#include 
#define F_CPU 1000000 /* 1MHz */
#include 
#define BAUD 9600 /* 9600bps */
#define SET_BAUD F_CPU/8/BAUD-1 // U2X=1
#define setbit(PORT,BIT) PORT|=_BV(BIT)
#define clearbit(PORT,BIT) PORT&=~_BV(BIT)
#define checkbit(PORT,BIT) (PORT&_BV(BIT))
// LCD
#define LCD_PORT PORTD
#define LCD_DDR DDRD
#define LCD_MASK 0x3c // data PD 2-5
#define LCD_RS 1 //PA
#define LCD_RS_PORT PORTA //PA
#define LCD_RS_DDR DDRA //PA
#define LCD_RW 0 //PA
#define LCD_RW_PORT PORTA //PA
#define LCD_RW_DDR DDRA //PA
#define LCD_EN 6 //PD
#define LCD_EN_PORT PORTD //PD
#define LCD_EN_DDR DDRD //PD
static volatile unsigned char lcd_buf[16]="123456789012345";
void lcd_send(unsigned char c){
  //  c=((c&0x0f)<<4)|((c&0xf0)>>4); //reverse
  //  c=((c&0x33)<<2)|((c&0xcc)>>2); //reverse
  //  c=((c&0x55)<<1)|((c&0xaa)>>1); //reverse
  c>>=2;
  c&=LCD_MASK;
  setbit(LCD_EN_PORT,LCD_EN);
  LCD_PORT=(LCD_PORT&~LCD_MASK)|c;
  clearbit(LCD_EN_PORT,LCD_EN);
  _delay_us(1);
}
void lcd_command8(unsigned char c){
  clearbit(LCD_RS_PORT,LCD_RS);
  clearbit(LCD_RW_PORT,LCD_RW);
  lcd_send(c);
  _delay_us(100);
}
void lcd_command(unsigned char c){
  //while(busy_address()&0x80){_delay_us(1);}
  clearbit(LCD_RS_PORT,LCD_RS);
  clearbit(LCD_RW_PORT,LCD_RW);
  lcd_send(c);
  lcd_send(c<<4);
  _delay_us(100);
}
void lcd_write(unsigned char c){
  setbit(LCD_RS_PORT,LCD_RS);
  clearbit(LCD_RW_PORT,LCD_RW);
  lcd_send(c);
  lcd_send(c<<4);
}
void lcd_display(){
  unsigned char i,j;
  i=0;
  for(j=0;j<0x48;j++){
    if(j==0x08){j=0x40;}
    lcd_command(0x80+j); // DDRAM
    lcd_write(lcd_buf[i++]);
  }
  lcd_command(0x0f); // display
}
void lcd_shift(unsigned char s){
  unsigned char n;
  for(n=0;n<15;n++){ lcd_buf[n]=lcd_buf[n+1]; }
  lcd_buf[15]=s;
  lcd_display();
}
void lcd_init(){
  _delay_ms(15);
  LCD_PORT=0;
  setbit(LCD_RS_DDR,LCD_RS);
  setbit(LCD_RW_DDR,LCD_RW);
  setbit(LCD_EN_DDR,LCD_EN);
  //  LCD_DDR=0x0f|_BV(LCD_RS)|_BV(LCD_RW)|_BV(LCD_EN) ;
  LCD_DDR|=LCD_MASK;
  _delay_ms(15);
  lcd_command8(0x30);
  _delay_us(4000);
  lcd_command8(0x30);
  lcd_command8(0x30);
  lcd_command8(0x20); // 4bit
  lcd_command(0x2c);  // 4bit
  //command(0x07); // mode,shift
  lcd_command(0x06); // mode,no shift
  lcd_command(0x01); // clear
  lcd_command(0x02); // home
  lcd_command(0x0f); // display
}
void disp_num(unsigned char c){
  unsigned char i;
  //  lcd_shift(0x20);
  i=c>>4;
  lcd_shift(i+((i<10)?0x30:0x37));
  i=c&0x0f;
  lcd_shift(i+((i<10)?0x30:0x37));
}
/* rs232c */
void init_rs232c(){
  UBRRH=0;
  UBRRL=SET_BAUD;
  _delay_ms(5);
  setbit(UCSRA,U2X); /* double speed */
  setbit(UCSRB,RXEN); /* RXCIE,TXCIE,UDRIE,RXEN,TXEN */
  setbit(UCSRB,RXCIE); /* RXCIE,TXCIE,UDRIE,RXEN,TXEN */
  setbit(UCSRC,USBS); /* 2 stop bits */
  setbit(UCSRC,UCSZ0); /* 8bit*/
  setbit(UCSRC,UCSZ1); /* 8bit*/
  clearbit(UCSRB,UCSZ2); /* 8bit*/
}
char receive_data(){
  while(checkbit(UCSRA,RXC)==0){} /* received */
  return UDR;
}
ISR(USART_RX_vect){ /* recieved */
  char c;
  c=receive_data();
  disp_num(c);
}
int main()
{
  unsigned char i,j;
  _delay_ms(9000);
  init_rs232c();
  lcd_init();
  sei();
  for(;;);
}
次は、PS2のモニターを作ろうと思うが、なかなか時間が取れないので、なかなか進まないかな。
[]