Professional Documents
Culture Documents
Đo nhiệt độ dùng DS18B20,đo khoảng cách, giao tiếp máy tính, hiển thị LCD.
Lời mở:
Mình hy vọng đề tài này sẽ giúp cho bạn hiểu thêm về lập trình cho Avr. Mình đã bước
đầu làm quen với Avr và gặp nhiều khó khăn, mất nhiều time (và cả $) cho việc làm quen, mong
rằng tài liệu này sẽ giúp bạn tiếp cận Avr nhanh hơn .Tất cả phần cứng và code mình đã làm và
chạy OK.
Cuối cùng xin cảm ơn diễn đàn dientuvietnam.net đã cho mình học hỏi rất nhiều
kiến thức. Đặc biệt là mod Sphinx,( xin cảm ơn nhân sư của Pnlab :D )
CHÚ Ý : Tài liệu này chỉ dành cho newbie ,chứ các bác cao thủ mà đọc thì em lấy làm xấu
hổ lắm.
www.dientuvietnam.net
http://vagam.dieukhien.net/
LCD:
1. http://dientuvietnam.net/forums/showthread.php?t=281&highlight=L%E1%BA%ADp
+tr%C3%ACnh+hi%E1%BB%83n+th%E1%BB%8B+LCD+b%E1%BA%B1ng+Asse
mbler+%28+tutorial%29
2. http://www.vagam.dieukhien.net/discuss.php?thid=3121&pagenum=2
3. http://vagam.dieukhien.net/discuss.php?thid=148&pagenum=1
RS232
4. http://www.8051projects.net/serial-communication/introduction.php
5. http://www.vagam.dieukhien.net/discuss.php?thid=3216&pagenum=1
6. http://dientuvietnam.net/forums/forumdisplay.php?f=74
1
Duongv3@gmail.com Lest’s Share to be Shared
Phần cứng :
Dưới đây là cái mạch của mình .
2
Duongv3@gmail.com Lest’s Share to be Shared
3
Duongv3@gmail.com Lest’s Share to be Shared
Phần mềm:
Bây giờ lập trình nào, mình chia làm 2 phần : trên AVR (mình dùng CodeVisionAvr)và
trên PC (dùng Vb6 :D).
CodeVision AVR:
Mình kết hợp adc và ds18B20 bị lỗi (cũng không biết tại sao, bạn giải quyết được nhớ
chỉ cho mình nhé) nên mình lập trình 2 code riêng 1 code đo nhiệt độ và 1 code ADC.
4
Duongv3@gmail.com Lest’s Share to be Shared
Và
Chọn chip
5
Duongv3@gmail.com Lest’s Share to be Shared
6
Duongv3@gmail.com Lest’s Share to be Shared
7
Duongv3@gmail.com Lest’s Share to be Shared
8
Duongv3@gmail.com Lest’s Share to be Shared
Cấu hình cổng OUT cho các PORTA.2 và PORTA.4 để báo hiệu ra LED và Loa
Sau đó vào menu vào như trong hình rồi chọn tên file để save
9
Duongv3@gmail.com Lest’s Share to be Shared
Bây giờ ta đã có code c/t tự dịch . Đầu tiên là phải thay dòng #include
<ds1820.h> bằng #include <ds18b20.h> (đơn giản vì ta dùng IC 18B20).
/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.4 Standard
Automatic Program Generator
© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 6/23/2009
Author : DuongV3
Company : DHBK
Comments: Have A Mice Day
#include <mega16.h>
#include <delay.h>
10
Duongv3@gmail.com Lest’s Share to be Shared
#include <ds18b20.h>
#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7
11
Duongv3@gmail.com Lest’s Share to be Shared
#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif
#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
12
Duongv3@gmail.com Lest’s Share to be Shared
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif
#if TX_BUFFER_SIZE<256
unsigned char tx_wr_index,tx_rd_index,tx_counter;
#else
unsigned int tx_wr_index,tx_rd_index,tx_counter;
#endif
#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
{
while (tx_counter == TX_BUFFER_SIZE);
#asm("cli")
if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0))
13
Duongv3@gmail.com Lest’s Share to be Shared
{
tx_buffer[tx_wr_index]=c;
if (++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;
++tx_counter;
}
else
UDR=c;
#asm("sei")
}
#pragma used-
#endif
14
Duongv3@gmail.com Lest’s Share to be Shared
};
}
};
}
void locso(float so)
{
// unsigned char t,c,d,tp1,tp2,tp3,tp4;
float temp1,temp2;
// t=so/100;
// lay fan tram
c=so/10;
// lay fan chuc
d=(so-10*c);
// lay hang don vi
if(so<0)
15
Duongv3@gmail.com Lest’s Share to be Shared
temp2=so*-1;
else
temp2=so;
temp1=temp2-(c*10+d);
tp1 = (unsigned char)(temp1*10);
tp2 = (unsigned char)(temp1*100-tp1*10);
tp3 = (unsigned char)(temp1*1000-tp1*100-tp2*10);
tp4 = (unsigned char)(temp1*10000-tp1*1000-tp2*100-tp3*10);
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;
// Port D initialization
16
Duongv3@gmail.com Lest’s Share to be Shared
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
17
Duongv3@gmail.com Lest’s Share to be Shared
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0xD8;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x19;
18
Duongv3@gmail.com Lest’s Share to be Shared
lcd_clear();
lcd_gotoxy(0,0);
lcd_putsf("DuongV3");
lcd_gotoxy(0,1);
lcd_putsf("T(C)= ");
define_char(char0,0);
delay_ms(1000);
i=0;
max=35;
min=30;
while (1)
{
if (rx_counter>0){
kt=getchar(); //kt tra ve se la gia tri trong bang ASCii
// lcd_putchar(kt);
array[i]=getnum(kt)-48;
++i;
}
if(i==2)
{
max=array[0]*10+array[1];
}
if(i==4)
{
i=0;
min=array[2]*10+array[3];
array[0]=0;
array[1]=0;
array[2]=0;
array[3]=0;
}
// Chon so max, min
if (max<min)
{
t_g=max;
19
Duongv3@gmail.com Lest’s Share to be Shared
max=min;
min=t_g;
}
//In ra LCD Gia tri max min
sprintf(lcd_buffer,"%d",max);
lcd_gotoxy(0,0);
lcd_putsf("Max= ");
lcd_puts(lcd_buffer);
sprintf(lcd_buffer,"%d",min);
lcd_gotoxy(8,0);
lcd_putsf("Min= ");
lcd_puts(lcd_buffer);
//
if(ds18b20_init(0,25,35,DS18B20_12BIT_RES))
{
tg= ds18b20_temperature(0);
// temp=(unsigned char) (tg);
if(tg==-9999)
{
}
else
{
lcd_gotoxy(6,1);
if(tg<0)
lcd_putchar(45);
else
lcd_putchar(43);
sprintf(lcd_buffer,"%.4f",tg);
lcd_puts(lcd_buffer);
lcd_putchar(0);
lcd_putsf("C");
delay_ms(80);
if(tg>max)
PORTA=0x10; //PORTA=0x14;
else if (tg<min)
PORTA=0x14;
else PORTA=0x00;
20
Duongv3@gmail.com Lest’s Share to be Shared
}
}
locso(tg);
putnum(c);
putnum(d);
putchar('.');
putnum(tp1);
putnum(tp2);
putnum(tp3);
putnum(tp4);
putchar(' ');
};
}
Bây giờ mình xin giải thích về lưu đồ thuật toán trong hàm main và vòng while(1) (ngại vẽ lắm
nên chỉ nói thôi).
Đầu tiên c/t sẽ từ khởi tạo cho ta ds18b20 và lcd.Sau đó viết lên dòng đầu tiên màn hình
dòng chữ DuongV3 (cái này thì tất nhiên bạn sẽ thay đổi thôi :D). Sau đó là viết lên dòng thứ 2
dòng chữ t(c) . Đặt giá trị i , max , min ban đầu để cảnh báo. Chi tiết về lập trình LCD, bạn
tham khảo ở trang sau :
http://www.vagam.dieukhien.net/discuss.php?thid=3121
http://vagam.dieukhien.net/discuss.php?thid=148&pagenum=1
Bây giờ là trong vòng while: Nhận ký tự từ cổng Com(nếu có) ghi 2 ký tự nhận được
vào mảng (2 ký tự này sẽ coi là 1 số max hoặc min) Sau đó nhận tiếp 2 ký tự nữa lưu vào mảng
(2 ký tự này sẽ coi là 1 số max hoặc min).,Hàm getnum là mình viết có tác dụng chuyển từ ký tự
sang số để lưu vào mảng so sánh 2 số và chọn max ,min Ghi ra LCD Nếu khởi tạo ban
đầu cho ds18b20 thành công gán tg cho nhiệt độ từ con ds18B20 Nếu dương ghi dấu “+”, nếu
âm ghi dấu “-” ,đưa giá trị ra LCD locso() có tác dụng chuyển số nhiệt độ có dạng xx.xxxx về
các số riêng phần chục , dv, thập phân tương ứng với các biến c,d,tp1,tp2,tp3,tp4 Hàm
putnum () mình viết có tác dụng đưa 1 số ra cổng COM . Vậy là hết nhỉ :D
21
Duongv3@gmail.com Lest’s Share to be Shared
22
Duongv3@gmail.com Lest’s Share to be Shared
Cấu hình giống trên các phần của chip, lcd , PORT còn ADC cấu hình như sau :
Ở đây mình dùng ADC 10bit nên nên ko tick vào ô “Use 8 bits”. Và mình chọn chân
ADC vào là ADC0 nên nó sẽ scan First =0 và Last = 0
Cuối cùng đây là code phần này.
#include <mega16.h>
23
Duongv3@gmail.com Lest’s Share to be Shared
#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7
24
Duongv3@gmail.com Lest’s Share to be Shared
#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif
#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
25
Duongv3@gmail.com Lest’s Share to be Shared
return data;
}
#pragma used-
#endif
#if TX_BUFFER_SIZE<256
unsigned char tx_wr_index,tx_rd_index,tx_counter;
#else
unsigned int tx_wr_index,tx_rd_index,tx_counter;
#endif
#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
{
while (tx_counter == TX_BUFFER_SIZE);
#asm("cli")
if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0))
{
tx_buffer[tx_wr_index]=c;
if (++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;
++tx_counter;
}
26
Duongv3@gmail.com Lest’s Share to be Shared
else
UDR=c;
#asm("sei")
}
#pragma used-
#endif
#include <delay.h>
#define FIRST_ADC_INPUT 0
#define LAST_ADC_INPUT 0
unsigned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];
#define ADC_VREF_TYPE 0x00
void putnum(int a)
{
switch(a){
case 0: putchar('0');
break;
case 1: putchar('1');
27
Duongv3@gmail.com Lest’s Share to be Shared
break;
case 2: putchar('2');
break;
case 3: putchar('3');
break;
case 4: putchar('4');
break;
case 5: putchar('5');
break;
case 6: putchar('6');
break;
case 7: putchar('7');
break;
case 8: putchar('8');
break;
case 9: putchar('9');
break;
};
}
void main(void)
{
unsigned int adc;
unsigned char lcd_buffer[10];
28
Duongv3@gmail.com Lest’s Share to be Shared
int
a[22]={497,464,420,385,360,330,307,290,266,248,230,224,211,209,198,194,189,182,17
8,170,167,167 },kc,i;
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x10;
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
29
Duongv3@gmail.com Lest’s Share to be Shared
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
30
Duongv3@gmail.com Lest’s Share to be Shared
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0xD8;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x19;
// ADC initialization
// ADC Clock frequency: 1000.000 kHz
// ADC Voltage Reference: AREF pin
// ADC Auto Trigger Source: None
ADMUX=FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff);
ADCSRA=0xCA;
// define_char(char0,0);
// define_char(char1,1);
// define_char(char2,2);
// lcd_putchar(0);
/* lcd_putsf("i");
lcd_putchar(1);
31
Duongv3@gmail.com Lest’s Share to be Shared
lcd_putsf("n t");
lcd_putchar(2);*/
while (1)
{
adc = adc_data[0];
for(i=0;i<=19;i++)
{
if(adc< a[i] && adc >a[i+1])
{
kc= i+10;
lcd_gotoxy(0,1);
break;
}
}
// lcd_gotoxy(0,1);
if(adc> a[0] || adc <a[19])
{ //lcd_clear();
lcd_gotoxy(0,1);
lcd_putsf("Ngoai Khoang ");
delay_ms(100);
}
else //if(adc< a[0] && adc >a[29])
{
sprintf(lcd_buffer,"Distance :%d",kc);
lcd_gotoxy(0,1);
lcd_puts(lcd_buffer);
lcd_putsf(" cm ");
locso(kc);
putnum(c);
putnum(d);
putchar(' ');
delay_ms(100);
};
};
}
32
Duongv3@gmail.com Lest’s Share to be Shared
Tất nhiên , khi lập trình bạn phải thay giá trị của mảng cũng như code trong vòng while
.
Code trên PC (phần này nêu qua thôi vì có trong Folder rồi):
Dim s As String
s = MSComm1.Input 'Temp
Text1.Text = s
End Sub
s = MSComm1.Input
Text2.Text = s
End Sub
MSComm1.Output = s
End Sub
s = Text4.Text 'Min
MSComm1.Output = s
End Sub
33
Duongv3@gmail.com Lest’s Share to be Shared
End
End Sub
MSComm1.CommPort = 1
MSComm1.Settings = "9600,n,8,1"
MSComm1.PortOpen = True
End Sub
Cách dùng : cho 2 số có 2 chữ số vào ô MAX , MIN sau đó click vào Button truyền
xuống LCD . Click vào nhiet do để đọc nhiet do.
Chú ý: để dùng cái này , phải tắt các tài nguyên đang dùng cổng Com như mạch nạp (có
thể) hoặc terminal của CodeVision. Và file .exe của mình bật lên rất là lâu mới lên (cũng ko biết
tại sao, KIS báo là virus :D )
Cuối cùng là 1 số chú ý (có thể bạn làm làm giống hệt trên cho vào mạch ko chạy thì
chú ý 1 số lỗi hay gặp sau):
1. Điều đầu tiên là xem lại mạch, kiểm tra các chân LCD và PORTB, AVR với
MAX232, MAX 232 với cổng COM .. ,Ban đầu mình truyền toàn ký tự lỗi , hóa
ra hàn cổng Com chưa chắc ( nhất là chân nối GND ) :D
2. Bạn đã cấu hình cho hàm sprintf chưa ?.
34
Duongv3@gmail.com Lest’s Share to be Shared
3. Cấu hình cho dao động 4Mhz dao động trong cho AVR .
Mình dùng mạch nạp AVR 910 dùng AVRProg cấu hình như sau :
4.
Clcick vào Advance
35
Duongv3@gmail.com Lest’s Share to be Shared
Và nếu là mạch nạp khác , bạn phải chọn Fuse bits, chi tiết xem tại trang sau: (vì
tôn trọng bản quyền mà nên mình sẽ không nói):
http://www.dientuvietnam.net/forums/showthread.php?t=4182
Mình chú ý bạn 1 bảng trong datasheet thôi:
Và
5. Cái code Vision rất là khó hiểu,ban đầu bạn viết code OK sau đó
chỉ thay đổi 1 số thứ nó không chạy đem trở về giá trị ban đầu lần này ko
chạy thật. Vì vậy kinh nghiệm của mình là viết code OK thì copy, coi là ver 1 sau
đó muốn sửa gì thì sửa . VD như : với code Ok nếu bạn thay thanh ghi UBRRL
và UBRRH thì phần giao tiếp máy tính sẽ ko chạy (tất nhiên), bạn đưa nó về giá
trị ban đầu nó sẽ vẫn ko chạy:D. À ,mà nhân đây nói giao tiếp máy tính, mình
nói luôn cách tính UBRRL và UBRRH khi chọn thạch anh . Công thức sẽ là
36
Duongv3@gmail.com Lest’s Share to be Shared
UBRR =( Tần số thạch anh /9600*16) -1. Sau đó sẽ cho vào phần High và low
của UBRR (ở đây là số hệ 16 (0x) ).
6. Cuối cùng nếu nó vẫn ko chạy, hãy liên lạc với mình , mình sẽ cố
gắng giúp :D duongv3@gmail.com .
7. Và nữa là : Code mình viết không hoàn toàn tối ưu, cả trên vi điều
khiển lẫn PC (nhất là trên PC , mình viết vội trong 1 đêm :D ) . Bạn nếu cải tiến
thì share luôn cho mình để mình học tập nhé. Mà quên, ngay cả bài này mình
cũng viết vội nên nếu sai về chính tả, bạn bỏ qua nhé ^-^
37