液晶の活用
ワンチップ磁気センサー
この間、デジットで買ったOPTREXのPWB842Bという液晶をようやく動かすことができた。いろいろとバグがあって発見に手間取ってしまった。まずwaitをかなり入れないとuPD7225がうまく応答しない。ICの説明書は一応読んだが、数マイクロ秒待てば良いような感じだったと思うが、100マイクロ秒ぐらいのwaitをいろいろなところに入れた。次に発見に手間取ったのが、i++のようなつもりで、i>>1としていたが、当然のことながらi>>=1としなければいけなかった。
さて、この液晶を何に使うかを考えていたのだが、磁気センサーを作ることにした。ホール素子の電圧をattiny261のADコンバーターを使って読んで、さらに液晶と通信して表示すれば、ワンチップの磁気センサーができあがるはずである。というわけで、プログラムを書いてみた。そのままだと精度が出ないようだったので、256回測定してその平均を取ったが、数値が安定して良い感じになった。磁場の絶対値に関しては、換算がまだ間違っているかも知れないが、1-1000ガウスぐらいは測定できるようになった。100以上では増幅をしないようにプログラムすれば、3Tぐらいまでは測れるようになつはずだろうが、面倒なので組み込んでいない。本当は、超伝導磁石の漏れ磁場を測定したかったのだが、どうやら感度の問題で難しいようだ。
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1000000 /* 1MHz */
#include <util/delay.h>
#include <avr/pgmspace.h>
/* lcd controller for OPTREX PWB842B */
/* 7seg 10digit */
// pin connection
// 1 /RESET
// 2 /SCK
// 3 SI
// 4 /BUSY
// 5 C,/D
// 6 /CS
// 7 Vdd 5V
// 8 Vss GND
#define LCD_PORT PORTB
#define LCD_PIN PINB
#define LCD_DDR DDRB
#define LCD_RESET 6
#define LCD_SCK 5
#define LCD_SI 4
#define LCD_BUSY 3
#define LCD_CD 2
#define LCD_CS 1
#define setbit(PORT,BIT) PORT|=_BV(BIT)
#define clearbit(PORT,BIT) PORT&=~_BV(BIT)
#define checkbit(PORT,BIT) (PORT&_BV(BIT))
#define SIZE_BUF 10
#define SIZE_CHAR 10
volatile uint8_t buf[SIZE_BUF]; // data to send LCD
static volatile uint8_t chars[SIZE_CHAR]; // charactor data
static volatile int32_t ave=0;
static volatile uint16_t cnt=0;
#define SIZE_AVE 256
#define ZERO_ADJ 6
const prog_uint8_t number[0x40]={
// 76543210
0b000000000, // 0x20
0b0, //! 0x21
0b001000001, //" 0x22
0b0, //# 0x23
0b0, //$ 0x24
0b0, //% 0x25
0b0, //& 0x26
0b001000000, //' 0x27
0b011001000, //( 0x28
0b000001011, //) 0x29
0b0, //* 0x2a
0b0, //+ 0x2b
0b0, //, 0x2c
0b000010000, //- 0x2d
0b000000100, //. 0x2e
0b010010001, /// 0x2f
// 76543210
0b011101011, //0 0x30
0b000000011, //1 0x31
0b010111001, //2 0x32
0b000111011, //3 0x33
0b001010011, //4 0x34
0b001111010, //5 0x35
0b011111010, //6 0x36
0b000001011, //7 0x37
0b011111011, //8 0x38
0b001111011, //9 0x38
0b0, //: 0x3a
0b0, //; 0x3b
0b001011000, //< 0x3c
0b000011000, //= 0x3d
0b000011001, //> 0x3e
0b000111001, //? 0x3f
// 76543210
0b010111011, //@ 0x40
0b011011011, //A 0x41
0b011110010, //B 0x42
0b010110000, //C 0x43
0b010110011, //D 0x44
0b011111000, //E 0x45
0b011011000, //F 0x46
0b011101010, //G 0x47
0b011010010, //H 0x48
0b000000010, //I 0x49
0b010100011, //J 0x4a
0b011010001, //K 0x4b
0b011100000, //L 0x4c
0b010011010, //M 0x4d
0b010010010, //N 0x4e
0b010110010, //0 0x4f
// 76543210
0b011011001, //P 0x50
0b001011011, //Q 0x51
0b010010000, //R 0x52
0b001010010, //S 0x53
0b011110000, //T 0x54
0b010100010, //U 0x55
//0b011100011, //V 0x56
0b011110011, //V 0x56
//0b001110001, //W 0x57
0b010101010, //W 0x57
0b011010011, //X 0x58
0b001110011, //Y 0x59
0b010010001, //Z 0x5a
0b011101000, //[ 0x5b
0b0, //\ 0x5c
0b000101011, //] 0x5d
0b001001001, //^ 0x5e
0b000100000 //_ 0x5f
};
void lcd_write(uint8_t *s,char n){
unsigned char i,c;
_delay_us(50);
clearbit(LCD_PORT,LCD_CS);
_delay_us(100); // wait at least 1.5us
do{
c=*(s++);
while(checkbit(LCD_PIN,LCD_BUSY)==0){}
_delay_us(100);
for(i=1<<7;i!=0;i>>=1){
clearbit(LCD_PORT,LCD_SCK);
_delay_us(50);
if((c&i)!=0){setbit(LCD_PORT,LCD_SI);}
else{clearbit(LCD_PORT,LCD_SI);}
_delay_us(50);
setbit(LCD_PORT,LCD_SCK);
_delay_us(50);
}
_delay_us(50); // wait at least 3us in total
}while((--n)>0);
while(checkbit(LCD_PIN,LCD_BUSY)==0){}
setbit(LCD_PORT,LCD_CS);
_delay_us(50);
}
void lcd_init(){
uint8_t commands[6]={
0b01001000, // mode_set
0b00110001, // synchronized transfer
0b00100000, // clear data memory
0b00011000, // blinking off
0b00010001, // display on
0b00010100, // without segment decoder
};
LCD_DDR|=(1<<LCD_RESET)|(1<<LCD_SCK)|(1<<LCD_SI)|(1<<LCD_CD)|(1<<LCD_CS);
LCD_DDR&= ~(1<<LCD_BUSY);
LCD_PORT|=(1<<LCD_RESET)|(1<<LCD_SCK)|(1<<LCD_SI)|(1<<LCD_CD)|(1<<LCD_CS);
// LCD_PORT|=(1<<LCD_BUSY);
_delay_us(100);
clearbit(LCD_PORT,LCD_RESET);
_delay_us(100);
setbit(LCD_PORT,LCD_RESET);
_delay_us(200);
setbit(LCD_PORT,LCD_CD);
_delay_us(100);
lcd_write(commands,6);
}
void buf_clear(){
unsigned char i;
for(i=0;i<SIZE_BUF;i++){buf[i]=0x00;}
}
void buf_display(){
clearbit(LCD_PORT,LCD_CD);
_delay_us(100);
lcd_write((uint8_t*)buf,SIZE_BUF);
}
void char_set(char n,unsigned char c){
chars[n]=c;
if(c<0x20 || c>0x7f){c=0x20;}
buf[n]=pgm_read_byte(&number[c-0x20]);
}
void char_shift(char s){
unsigned char n;
for(n=SIZE_CHAR-1;n>0;){ char_set(n,chars[--n]); }
char_set(0,s);
}
void string_set(char *s){
unsigned char c;
for(c=SIZE_CHAR;c>0;){
char_set(--c,*(s++));
}
buf_display();
}
void string_shift(char *s,char l){
for(;l>0;l--){
char_shift(*(s++));
buf_display();
_delay_ms(500);
}
}
void disp_num(unsigned char c){
unsigned char i;
i=c>>4;
char_shift(i+((i<10)?0x30:0x37));
i=c&0x0f;
char_shift(i+((i<10)?0x30:0x37));
buf_display();
}
// AD converter
void ad_init(){
clearbit(ADCSRB,REFS2); // 1.1V
setbit(ADMUX,REFS1); // 1.1V
clearbit(ADMUX,REFS0); // 1.1V
setbit(ADMUX,ADLAR); // bit6-15
setbit(ADCSRB,MUX5); //
clearbit(ADMUX,MUX4); //
clearbit(ADMUX,MUX3); //
clearbit(ADMUX,MUX2); //
clearbit(ADMUX,MUX1); //
clearbit(ADMUX,MUX0); //
setbit(ADCSRA,ADPS2); // CK/128
setbit(ADCSRA,ADPS1); // CK/128
setbit(ADCSRA,ADPS0); // CK/128
setbit(ADCSRA,ADEN); // enable
setbit(ADCSRA,ADIE); // interupt enable
setbit(ADCSRB,BIN); // bipolar
setbit(ADCSRB,GSEL); // gain 32/20
}
ISR(ADC_vect){
int16_t v;
uint8_t s[10];
v=ADCL;
v|=ADCH<<8;
v-=ZERO_ADJ<<6; // zero adjust
if(ave<0){v=-v;ave-=v>>6;}
else{ave+=v>>6;}
if(++cnt>=SIZE_AVE){
if(ave<0){ave=-ave;s[0]='-';}
else{s[0]=' ';}
ave/=(SIZE_AVE/2);
s[9]=' ';
s[8]='E';
s[7]='0';
s[6]=' ';
s[5]=ave%10+0x30;
ave/=10;
s[4]=ave%10+0x30;
ave/=10;
s[3]=ave%10+0x30;
ave/=10;
s[2]=ave%10+0x30;
ave/=10;
s[1]=ave%10+0x30;
string_set(s);
ave=0;
cnt=0;
}
}
int main(){
_delay_ms(500);
lcd_init();
buf_clear();
buf_display();
ad_init();
sei();
for(;;){
setbit(ADCSRA,ADSC); // enable
while(checkbit(ADCSRA,ADSC)!=0){_delay_us(1);}
_delay_us(10);
}
}