Giới thiệu chung về vi điều khiển micro controller Trước khi nói về vi điều khiển, chúng ta sẽ xem xét lại thế nào là máy tính: Máy tính nói chung là thiết bị dùng để xử lý, thu nhận, lư
Trang 1PHẦN III
Vi điều khiển H8/3069F
1 Giới thiệu chung về vi điều khiển (micro controller)
Trước khi nói về vi điều khiển, chúng ta sẽ xem xét lại thế nào là máy tính:
Máy tính nói chung là thiết bị dùng để xử lý, thu nhận, lưu trữ và truyền tải dữ liệu
Dữ liệu có thể là các ký tự trong một văn bản, hình ảnh, âm thanh… hay cũng có thể là các trạng thái của một thiết bị điện tử như nhiệt độ tủ lạnh, trạng thái của nồi cơm điện… Nhưng dù dữ liệu có là đại lượng gì đi nữa thìtất cả chúng đều được lưu trữ trong máy tính dưới dạng các dãy số 0 và 1.Một máy tính nói chung được cấu tạo bởi các thành phần như dưới đây:
Bộ xử lý (Processor): Chịu trách nhiệm điều khiển tất cả hoạt động của
hệ thống như xử lý số liệu, đóng ngắt các cổng…
Bộ nhớ chương trình (Program memory): Lưu trữ các mệnh lệnh để
CPU có thể biết phải làm gì
Bộ nhớ dữ liệu (Data memory): Chứa các dữ liệu tạm thời trong quá trình hoạt động
Các cổng vào ra (I/O interface): Là nơi để máy tính có thể giao tiếp với thế giới bên ngoài
Thế giới máy tính có rất nhiều loại, nhưng chúng ta có thể nhận biết 2 loại lớn
Processor(Pentium IV)
Program Memory(ROM, HDD)
Data Memory(RAM)
I/O interface
(USB port, COM port)
Trang 2 Máy tính để bàn: Đây là cái đầu tiên xuất hiện trong đầu khi bạn nghe nói đến từ máy tính Nhưng thực tế thì loại này chỉ chiếm một phàn nhỏ trong thế giới máy tính.
Loại thứ 2 là máy tính nhúng (embedded computer) – là những máy tínhđược tích hợp vào trong các thiết bị khác để đảm nhiệm việc điều khiển,
đo lường… Số lượng máy tính nhúng này lớn hơn rất nhiều so với máy tính để bàn, nhưng lại ít được biết đến hơn
Do máy tính nhúng được tích hợp vào một sản phẩm, và để làm một tác
vụ nhất định, nên không cần phải mạnh Nó cần phải có giá rẻ nhất có thể.Thông thường, để giảm giá thành, máy tính nhúng được tích hợp tất cả các bộ phận (CPU, RAM, ROM…) trong một con chip Thể loại máy tính này thường được gọi dưới một tên khác là vi điều khiển (micro controller)
Thông thường, để phát triển ứng dụng cho vi điều khiển, người ta sẽ viết chương trình trên máy tính PC (dùng ngôn ngữ C chẳng hạn) Sau đó, sử dụng chương trình dịch để dịch ra mã máy mà vđk có thể hiểu được Các mãmáy đó sẽ được ghi vào vđk và được vđk thực hiện
Máy tính để bàn, thứ mà bạn nghĩ đến khi
nghe từ “máy tính”
Embedded computer: Số lượng nhiều
nhưng ít được biết.
All in one IC
Trang 32 Khái quát về vi điều khiển H8/3069F
Vi điều khiển H8/3069F là một vđk thuộc họ H8/300H của hãng Renesas
Họ CPU H8/300H có cấu trúc trong 32 bit, bao gồm 16 thanh ghi chung
16 bit Các thanh ghi này có thể được chia ra thành các thanh ghi 8 bit hoặc kết hợp lại thành thanh ghi 32 bit
H8/300H có tập lệnh gồm 62 lệnh, với khả năng tình toán toán học và logic với 8/16/32 bit cùng với khả năng thao tác đến bit (bit manipulation).CPU này có thể định được 16MB địa chỉ
Sau đây là một số spec của vđk H8/3069F
- Tần số lớn nhất: 25MHz
- Thực hiện các lệnh trong 2 hoặc 4 chu kỳ
- Có lệnh nhân/chia 8/16/32 bit có dấu
- 512KB ROM, 16KB RAM
- 7 ngắt ngoài, 36 ngắt trong, 3 level ngắt
- Có thể đinh địa chỉ tới 16MB, có thể truy xuất bộ nhớ ngoài với 8 đường CS riêng biệt Mỗi vùng có thể truy xuất với độ rộng 8 hoặc
16 bit
- Có thể truy xuất trực tiếp 8MB DRAM
- 3 timer 16 bit, 4 timer 8 bit
- 3 bộ truyền nhận nối tiếp (SCI)
- 8 kênh A/D 10 bit
- 2 kênh D/A 8 bit
- 70 cổng vào/ra và 9 cổng vào
H8/3069F có thể hoạt động ở 6 mode khác nhau Các mode được lựa chọn dựa vào các chân MD0-MD2 Các mode có không gian bộ nhớ khác nhau
Trang 44 Lập trình điều khiển các chân vào/ra
Trong phần này, chúng ta sẽ học cách làm cho các chân của vđk thành mức logic cao/thấp, hay đọc mức logic vào từ các chân
Như phần giới thiệu trước chúng ta thấy rằng H8/3069 có 79 chân vào/ra Nhưng một phần chúng đã được sử dụng vào mục đích khác như bus địa chỉ, ADC…
Cách truy xuất đến các cổng vào/ra này là gần giống như nhau Do đó, chúng ta sẽ lấy port P4 lam ví dụ
Các chân vào/ra này được truy xuất thông qua các thanh ghi tương ứng Các thanh ghi này được truy xuất trực tiếp bằng địa chỉ của nó
Chúng ta thao tác đến các chân của port 4 thông qua các thanh ghi sau:
Trang 5- P4DDR: Thanh ghi hướng – Đây là 1 thanh ghi có 8 bit, tương ứng với 8 chân P4_0 -> P4_7 của Port 4 Nếu bit là 0 thì chân tương ứng dùng để đọc giá trị vào, và nếu là 1 thì dùng để xuất ra
- P4DR: Thanh ghi dữ liệu – Dùng để ghi giá trị cần xuất ra hay đọc giá trị từ pin tương ứng vào
- P4PCR: Thanh ghi xác định điện trở kéo lên của các chân Nếu bit tương ứng là 1, thì ở chân đó sẽ có 1 điện trở nối lên dương nguồn Nếu là 0 thì điện trở đó sẽ không tồn tại
Thông thường, các thanh ghi như thế này đã được định nghĩa trước, và ta chỉ việc thay đôi thông qua việc thao tác đến tên của nó Trong trường hợp của chúng ta, các thanh ghi này được định nghĩa ở file iodefine.h
Các thanh ghi này thường được định nghĩa theo dạng union nên chúng ta
có thể truy xuất đến nó theo byte hoặc bit rất dễ dàng
Ví dụ đối với port 4:
union un_p4dr { /* union P4DR */
unsigned char BYTE; /* Byte Access */
struct { /* Bit Access */
unsigned char B7:1; /* Bit 7 */
unsigned char B6:1; /* Bit 6 */
unsigned char B5:1; /* Bit 5 */
unsigned char B4:1; /* Bit 4 */
unsigned char B3:1; /* Bit 3 */
unsigned char B2:1; /* Bit 2 */
unsigned char B1:1; /* Bit 1 */
unsigned char B0:1; /* Bit 0 */
Ví dụ: P4DDR.BYTE=0xF0; //Chân 7~4 là chân ra, 3~0 là chân vào
#define P4DR (*(volatile union un_p4dr *)0xFFFFD3) /* P4DR Address*/
Trang 6Tương tự, câu lệnh này định nghĩa P4DR là giá trị của ô nhớ tại địa chỉ 0xFFFFD3 Nhưng kiểu con trỏ ở đây là kiểu union un_p4dr nên chúng ta
có thể truy xuất đến nói theo byte hoặc bit
Ví dụ:
P4DR.BYTE=0x00;//Cho cả port 4 thành 0Hay P4DR.BIT.B7=1;//Set chân thứ 7 của port thành 1
#define P4PCR (*(volatile union un_p4pcr *)0xFEE03E) /* P4PCR Address*/
Thanh ghi P4PCR cũng được định nghĩa theo kiểu của P4DR như trên
Luyện tập: Trong mạch phát triển của chúng ta, LED 7 thanh U101 được
nối với cổng P4 như hình dưới Hãy lập trình để nó hiện lần lượt các số từ 0 đến 9, sau đó lặp lại
Ví dụ, làm cho tất cả các thanh LED đều sáng:
void main(void)
{
P4DDR.BYTE=0xFF; //Tat ca cac chan cua P4 la cong ra
P4DR.BYTE=0x00; //Cho tat ca cac chan cua P4 xuong 0
}
5 Sử dụng external bus để mở rộng cổng xuất/nhập.
Đối với các vđk có bus mở rộng (truy xuất bộ nhớ ngoài) nói chung, và vđk H8/3069 nói riêng, chúng ta có thể thêm nhiều cổng I/O bằng cách dùngcác IC thích hợp
Để truy xuất bộ nhơ ngoài, vđk sẽ thực hiện các thao tác sau:
Đối với ghi dữ liệu ra bộ nhớ ngoài:
1) Đặt địa chỉ cần truy cập lên bus địa chỉ
2) Đặt dữ liệu cần ghi lên bus dữ liệu
Trang 73) Xuất 1 số chân tín hiệu để báo ghi (Trong trường hợp H8/3069 chúng
ta đang nghiên cứu, chân HWR sẽ được kéo xuống thấp để báo bắt đầu ghi)
Đối với đọc dữ liệu từ bộ nhớ ngoài:
1) Đặt địa chỉ cần truy cập lên bus địa chỉ
2) Xuất 1 số chân tín hiệu để báo đọc (Trong trường hợp H8/3069 chúng
ta đang nghiên cứu, chân RD sẽ được kéo xuống thấp để báo bắt đầu đọc)
3) Đọc dữ liệu từ bus địa chỉ vào các thanh ghi
Như vậy, bằng cách kết hợp các tín hiệu điều khiển + address một cách thích hợp, kết hợp với sử dung các bộ chốt/đệm 3 trạng thái, chúng ta có thể
mở rộng cổng vào/ra tùy ý (tất nhiên không phải là vô hạn )
Với H8/3069 ở mode 5 mà ta đang nghiên cứu, cấu trúc bộ nhớ của nó như sau:
Trang 8Khi truy cập đoạn bộ nhớ nào, chân CS tương ứng với khoảng bộ nhớ đó
sẽ xuống thấp
Ví dụ để đọc 1 byte từ địa chỉ 0x212345 (area 1)
1) Đặt giá trị 0x212345 ra bus địa chỉ
2) Đặt CS1 xuống thấp Hai bước 1) và 2) này xảy ra đồng thời
Khu vực bộ nhớ ngoài.
Trang 93) Cho chân RD xuống thấp.
4) Đọc bus dữ liệu vào trong vđk
Trong khóa học này, chúng ta sẽ sử dụng IC 74HC32 để giải mã địa chỉ, đệm 74HC541 và chốt 74HC273
Trong hình trên, chúng ta đưa 2 tín hiệu CS3 và RD qua bộ OR 74HC32 Tín hiệu ra là READ3 Như vậy, khi cả CS3 và RD xuống thấp đọc bộ nhớ ngoài ở địa chỉ nào đó trong khoảng 0x600000 đến 0x7FFFFF, chân READ3 sẽ xuống thấp Khi đó, các tín hiệu ở đầu vào của 74HC541 sẽ đượcđưa vào đầu ra (D15~D8) Khi vđk đọc bus dữ liệu, nó sẽ đọc được giá trị của các switch SW201~SW208
#include “h8stdio.h”
#define SW2 (*(volatile unsigned char *)0x200000) /* SW201~SW208 Address*/
#define LED2 (*(volatile unsigned char *)0x200001)
Trang 106 Bộ chuyển đổi tương tự sang số
H8/3069 có 8 kênh chuyển đổi AD 10 bits, với tốc độ chuyển đổi cao nhất đối với mỗi kênh là 2.8uS
Tại mỗi thời điểm, chỉ có duy nhất 1 kênh được chuyển đổi Nếu muốn lấy giá trị điện áp tương tự ở nhiều kênh khác nhau thì chỉ có cách duy nhất
là đọc lần lượt từng kênh một
Khoảng điện áp tương tự mà nó có thể chuyển đổi được được xác định qua chân Vref Nếu như chúng ta nối chân Vref với 5V, thì với điện áp chânvào là 5V, giá trị số nhận được là 1024 Nếu điện áp vào là x Vôn thì giá trị
số tương ứng là x/5*1024 1 đơn vị số sẽ tương ứng với 5/1024V = 4.9mV
Sơ đồ khối của bộ chuyển đổi AD
Có 10 thanh ghi liên quan đến bộ chuyển đổi ADC
Trang 118 thanh ghi data có thể truy xuất theo dạng 8 bits (ADDRAH và
ADDRAL) hoặc gộp lại để truy xuất theo kiểu 16 bits (ADDRA)
2 thanh ghi cuối cùng dùng để diều khiển hoạt động của bộ AD
b) Thanh ghi ADCR
Trang 12c) Thanh ghi data (ADDRA, ADDRB, ADDRC, ADDRD)
Các thanh ghi này dùng để lưu giá trị chuyển đổi Chỉ 10 bits cao của các thanh ghi này có ý nghĩa 6 bits thấp không sử dụng đến
Mỗi thanh ghi ADDR sẽ được dùng chung cho 2 chân vào Ví dụ, giá trị chuyển đổi cho chân AN0 được đọc từ thanh ghi ADDRA, cho chân AN6 ở thanh ghi ADDRC
Để có thể dùng ADC, chúng ta sẽ làm những bước sau(đối với chế độ single)
a) Thiết lập thanh ghi ADCSR, ADCR ở chế độ thích hợp
b) Thiết lập chân cần chuyển (CH0, CH1, CH2 trong thanh ghi ADDCSR)
c) Set bit ADST của thanh ghi ADCSR thành 1 để bắt đầu chuyển đổi
Trang 13d) Chờ đến khi bit ADF của ADCSR thành 1 (báo kết thúc chuyển đổi)
e) Xóa bit ADF của ADCSR thành 0 (để có thể chuyển đổi lần tiếp theo)
f) Đọc giá trị từ thanh ghi data (ADDRx) tương ứng
Ví dụ:
Trang 14/**************************************************************************************** Chuong trinh mo ta cach su dung ADC
AD.ADCSR.BIT.ADIE = 0; // Enable ADC interrupt 0=NO / 1=YES
AD.ADCSR.BIT.ADST = 0; // AD_START 1=Start convert
AD.ADCSR.BIT.CKS = 0; // Convertion clock 0=134 / 1=70
AD.ADCSR.BIT.SCAN = 0; // Scan mode 0=Single mode / 1=Scan mode AD.ADCSR.BIT.CH = 1; // Select input channle Single mode0=AN0, 1=AN1 ~ 7=AN7 AD.ADCR.BIT.TRGE = 0; // External trigger setting 0=NO / 1=YES
AD.ADCSR.BIT.ADST = 1; // ADC sampling start
while( AD.ADCSR.BIT.ADF == 0 ) // ADC convertion finish?
;
AD.ADCSR.BIT.ADF = 0; // ADC END Flag clear
switch( ch ) {
case 0 : ad_data = AD.ADDRA; break;
case 1 : ad_data = AD.ADDRB; break;
case 2 : ad_data = AD.ADDRC; break;
case 3 : ad_data = AD.ADDRD; break;
data=get_adc(i);
printf("CH%d=%d ",i,data);
} printf("\n");
Trang 157 Bộ chuyển đổi số sang tương tự
H8/3069F có 2 bộ chuyển đổi số sang tương tự (dùng để xuất điện áp tương tự ra ngoài)
Bộ chuyển đổi này có tốc độ cao nhất là 10uS với độ phân giải 8 bit Điện
áp Vref (tương ứng với giá trị số cao nhất 255) chung với điện áp Vref dùngcho bộ chuyển đổi ADC
Sơ đồ khối bộ chuyển đổi DA
Chúng ta có thể làm việc với bộ chuyển đổi DAC này thông qua 4 thanh ghi 2 thanh ghi điều khiển DACR và DASTCR cùng với 2 thanh ghi data DADR0 và DADR1
a) Thanh ghi DACR
Trang 16Khi DAE bằng 0 thì kênh nào có bit DAOE tương ứng bằng 1 sẽ được chuyển đổi Còn khi DAE bằng 1 thì cả 2 kênh đều được chuyển đổi
mà không phụ thuộc vào giá trị các bit DAOE
b) Thanh ghi DASTCR
Thanh ghi này chỉ dùng bit 0 là DASTE để cho phép hay không cho phép bộ DAC hoạt động trong chế độ standby
c) Thanh ghi DADR0 và DADR1
Các thanh ghi này lưu trữ giá trị số cần chuyển đổi sang điện áp tương tự cho kênh 0 và 1
Ví dụ, để xuất điện áp tương tự 2.5V ra chân DA1 (Vref = 5V)
1) Thiết lập thanh ghi DACR
Để điều khiển hoạt động của các bộ định thời này (ví dụ chọn mode hoạt động, tần số clock…) thì ta cần phải thiết lập các thông số dựa vào một số thanh ghi điều khiển khác
8.1 Chế độ cơ bản (đếm)
Ở chế độ này, thanh ghi TCNT sẽ tăng lên theo xung clock Khi giá trị thanh ghinày bằng giá trị trong thanh ghi GRA hoặc GRB thì TCNT sẽđược xóa về 0 đồng thời 1 cờ IMF sẽ được set thành 1
Trang 17Để dùng timer chạy trong chế độ này, chúng ta làm như sau (ví dụ đối với timer0)
a) Thiết lập các thông số:
ITU0.TCR.BIT.TPSC=3; // moi 8 xung clock cua he thong thi TCNT se tang len 1
// Co nghia la cu sau 0.32uS, TCNT se tang len 1 (voi thach anh 25MHz) ITU0.TCR.BIT.CCLR=1; // TCNT se duoc xoa ve 0 khi TCNT bang GRA
ITU0.GRA=3125; // 3125*0.32uS = 1mS => TCNT se duoc clear ve 0 sau moi 1mS
ITU0.TIOR.BYTE=0x00; // Khong co output ra chan cua vdk khi compare match (TCNT=GRA)
b) Start timer
ITU.TSTR.BIT.STR0=1; // Start timer0
c) Kiểm tra giá trị của cờ IMF Nếu như cờ này bằng 1 thì đã xảy ra sự kiện TCNT=GRA (hay GRB) Khi đó ta sẽ xóa IMF về 0 để bắt đầu chu trình tiếp theo, đồng thời thực hiện một tác vụ gì đấy
while (ITU.TISRA.BIT.IMFA0==0) // Cho den khi co IMFA0 duoc set bang 1
; ITU.TISRA.BIT.IMFA0=0; // Clear IMFA0 ve 0
i++;
Ví dụ sau sẽ thay đổi giá trị cua LED sau mỗi 1s
Trang 18ITU0.TCR.BIT.TPSC=3; // moi 8 xung clock cua he thong thi TCNT se tang len 1
// Co nghia la cu sau 0.32uS, TCNT se tang len 1 (voi thach anh 25MHz) ITU0.TCR.BIT.CCLR=1;// TCNT se duoc xoa ve 0 khi TCNT bang GRA
ITU0.GRA=3125; // 3125*0.32uS = 1mS => TCNT se duoc clear ve 0 sau moi 1mS
ITU0.TIOR.BYTE=0x00; // Khong co output ra chan cua vdk khi compare match (TCNT=GRA) }
int main (void)
{
unsigned int i,j;
init_timer_normal(); // Khoi tao timer0
ITU.TSTR.BIT.STR0=1; // Start timer0
} LED2=j;
j++;
}
}
8.2 Chế độ điều biến độ rộng xung.
Trong chế độ PWM, dạng sóng sẽ được xuất ra ở chân TIOCA Khi TCNT = GRA thì chân TIOCA sẽ xuất ra giá trị 1, còn khi TCNT = GRBthì TIOCA sẽ về 0
Giá trị của TCNT có thể được xóa về 0 khi TCNT=GRA hoặc
TCNT=GRB (phụ thuộc vào CCLR bits trong thanh ghi TCR) Và giá trị GRA hay GRB trong trường hợp đó sẽ chính là chu kì của xung ra
Trang 19Để sử dụng PWM chúng ta làm như sau:
a) Thiết lập:
/* Setup PWM 1 */
ITU1.TCR.BIT.TPSC=0x03; //Timer 1 clock = internal clock/8
ITU1.TCR.BIT.CCLR=0x02; //TCNT clear by GRB compare match
ITU1.GRB=0xFF; //Time for PWM output change to 0
ITU1.GRA=0x7F; //Time for PWM output change to 1
ITU1.TIOR.BIT.IOB=0; //No output at TIOCB1
b) Bắt đầu phát xung
ITU.TSTR.BIT.STR1=1; // Start timer1
c) Thay đổi độ rộng xung khi cần thiết
ITU1.GRA=x;
Chương trình ví dụ sau mô tả hoạt động của PWM1
Trang 20* In this program, we init PWM1
* TIOCB pins will be used for general purpose
ITU.TMDR.BIT.PWM1=1; //Set timer 1 in PWM mode }
while(1);
}