HỌC VIỆN KỸ THUẬT MẬT MÃ
KHOA ĐIỆN TỬ-VIỄN THÔNG
THỰC TẬP CƠ SỞ 2
Thực tập nhúng trên ARM
Giảng viên hướng dẫn
Dương Phúc Phần
1
LỜI NĨI ĐẦU
Lập trình nhúng hiện nay khơng xa lại gì với chúng ta, STM32 là chip của ST, dựa
trên nền lõi ARM Cortex-M. Dòng ARM Cortex™-M là thế hệ mới, thiết lập các
tiêu chuẩn mới về hiệu suất, chi phí, ứng dụng cho các thiết bị cần tiêu thụ năng
lượng thấp, và đáp ứng yêu cầu thời gian thực khắc khe. Được sự hướng dẫn của
thầy Dương Phúc Phần, nhóm 7 đã hồn thành 3 phần được giao bao gồm: Giới
thiệu Keil Arm, lập trình ADC/ DAC cho dịng STM32 và biên dịch nhân Linux.
Trong quá trình thực hiện đề tài vẫn cịn nhiều sai sót, mong nhận được nhiều ý
kiến đóng góp từ thầy .
2
PHẦN 1. GIỚI THIỆU KEIL-ARM
1.1.Sơ lược về KeilC
Ngày nay trên thị trường có khá nhiều trình biên dịch ngơn ngữ C cho các dòng vi
điều khiển, IAR, Keil C … Những phần mềm này được gọi là môi trường phát
triển tích hợp (IDE: viết tắt của Integrated Development Environment). Chúng
đóng vai trị như là trình soạn thảo ngơn ngữ C, assembly, cũng như là trình biên
dịch, hỗ trợ debug-phát hiện lỗi và sửa các câu lệnh vừa được viết ra. Ngoài ra
chúng cũng hỗ trợ biên dịch những câu lệnh đã được viết ra bởi người sử dụng
thành file hex qua đó nạp vào các dịng vi xử lý.
Trong đó Keil C là một phần mềm chuyên dụng để tạo ra một mơi trường lập trình
hỗ trợ cho nhiều dịng vi xử lý từ ARM, AVR, 8051, PIC,.. với 2 ngôn ngữ chủ yếu
là C và assembly.
Giao diện hoạt động của Keil C:
- Màn hình làm việc chính
3
Trên màn hình làm việc của Keil C có 3 vùng chính:
Vùng 1: Vùng soạn thảo. Đây là nơi ta sẽ soạn thảo chương trình. Người sẽ dụng
sẽ lập trình phần mềm tại đây
Vùng 2: Là vị trí của các cửa sổ Project, cho phép ta quản lý các tập tin trong dự
án, và cửa sổ Function, cho phép ta quản lý các chương trình con, thư viện,..
Vùng 3: Cửa sổ Build Output. Hiển thị các thông tin trong quá trình biên dịch
chương trình. Đây là nơi sẽ thể hiện các lỗi (error) và các cảnh báo (warning). Sau
khi debug project nếu như khơng có lỗi chương trình sẽ biên dịch xong và hiện lên
cửa số thông báo ở vùng 3 như ở dưới
Build chương trình
Sau khi soạn thảo chương trình xong, ta biên dịch chương trình bằng cách vào
menu Project\Build target hoặc nhấn nút Build trên thanh công cụ hoặc ta cũng có
thể nhấn phím F7. Nút Build được tơ đậm như trong hình bên dưới. Cơng dụng
của nút Build là biên dịch những đoạn chương trình được thay đổi xem chúng có
lỗi hay khơng.
4
Ngồi nút Build ra chúng ta cịn có nút Rebuild, nút Rebuild được dùng để biên
dịch tồn bộ chương trình bao gồm cả thư viên được add và cả chương trình main.
Tuy nhiên thời gian biên dịch của nút Rebuild thường lâu hơn Build, vị trí của
nút Rebuild trên thanh cơng cụ debug được tơ như hình bên dưới.
Sau khi chương trình tiến hành biên dịch chương trình, nếu khơng có lỗi xảy ra, ta
sẽ nhận được thơng báo 0 Error(s), 0 Warning(s) trong cửa sổ Buid Output sau khi
quá trình biên dịch hồn tất.
Trong q trình phát triển một chương trình, sẽ có hai loại lỗi (Error) có thể xảy ra:
Lỗi cú pháp (Syntax error): Lỗi này là các sai sót trong cấu trúc câu lệnh như thiếu
tham số, sai từ khóa … Các lỗi này sẽ được trình biên dịch tự động phát hiện trong
quá trình biên dịch.
Lỗi Logic (Error): Lỗi này là các sai sót trong giải thuật chương trình, làm cho
chương trình chạy khơng đúng ý đồ ban đầu của lập trình viên. Lỗi này chỉ có thể
do chính lập trình viên phát hiện và sửa chữa. Các IDE không thể trực tiếp phát
hiện các lỗi logic, nó chỉ cung cấp cho người dùng các cơng cụ hỗ trợ cho quá trình
phát hiện và sửa chữa loại lỗi này.
Debug chương trình
Keil C ngồi việc hỗ trợ ta soạn thảo và biên dịch chương trình, nó cịn hỗ trợ ta
một cơng cụ gỡ rối (Debug) chương trình hết sức hiệu quả.
Để chạy debug một chương trình sau khi đã biên dịch thành cơng, ta nhấn có thể
kích hoạt chức năng debug bằng một trong các cách sau:
5
Nhấn tổ hợp phím tắt Ctrl + F5.
Các cảnh báo warning, đây không phải là những error nên cho dù chương trình có
bao nhiêu warning đi nữa vẫn sẽ hoạt động hình thường. Các warning được dùng
để cảnh báo những câu lệnh có thể có lỗi tiềm ẩn, những câu lệnh không sử dụng
nhưng vẫn khai báo,..
Mở menu Debug-Start/Stop Debug Session
Để mở chức năng debuger ta nhấn vào nút được khoanh vùng như hình bên dưới.
Muốn tắt chức năng Debug, ta làm lại thao tác trên một lần nữa
Sau khi kích hoạt chức năng Debug, cửa sổ Keil C có dạng như hình dưới đây. Nếu
có cửa sổ nào khơng xuất hiện, ta có thể vào menu View để bật cửa sổ đó lên
6
Trong cửa sổ này, có 4 vùng chính như hình bên dưới:
7
Vùng 1: Cửa sổ thể hiện các thanh ghi của vi điều khiển
Vùng 2: Cửa sổ lệnh soạn thảo, chứa chương trình đang được debug
Vùng 3: Cửa sổ Watches cho phép ta theo dõi giá trị của các biến chứa trong
chương trình. Muốn biết giá trị của biến nào, ta chọn cửa sổ này và nhấn phím F2,
sau đó nhập tên của biến cần theo dõi. Lúc này, của sổ sẽ hiển thị tên biến cũng
như giá trị hiện tại của biến đó.
Vùng 4:Cửa sổ Disassembly : Cho ta biết chính xác một lệnh Keil C được viết
bằng hợp ngữ như thế nào. Kích hoạt cửa sổ này bằng cách vào menu
View/Disassembly.
Bên cạnh những chức năng trên Keil C còn hỗ trợ nhiều chức năng khác cho người
sử dụng chẳng hạn như.
8
Cửa sổ Memory Kích hoạt bằng menu View/Memory. Cho phép xem nội dung bộ
nhớ chương trình và bộ nhớ dữ liệu như hình bên dưới: Muốn xem bộ nhớ chương
trình bắt đầu từ một địa chỉ nào đó, ta nhập Địa chỉ vào ơ Address.
Ta cũng có thể quan sát trạng thái các Port, các Timer, ngắt bằng cách vào
menu Peripherals, chọn các đối tượng cần quan sát. Như ví dụ trong hình dưới đây,
các thanh ghi của GPIOA được hiển thị để ta quan sát trực tiếp giá trị khi chương
trình đang chạy:
9
Chạy Debug:
Sau khi đã kích hoạt đầy đủ các cửa sổ cần thiết, ta bắt đầu cho chạy debug bằng
cách chọn một trong các nút trên thanh công cụ Debug :
10
Nút Reset: Reset chương trình về trạng thái ban đầu
Run (F5): Thực thi chương trình
Step (F11): Thực thi từng dịng lệnh, có nhảy vào hàm con.
Step over (F10): thực thi từng dịng lệnh, khơng nhảy vào hàm con.
Step out (Ctrl + F11): Nhảy ra khỏi hàm con
Run to Cursor line (Ctrl + F10): Thực thi chương trình từ đầu cho đến vị trí con
trỏ.
1.2. Q trình tạo Project, biên dịch, kết quả
Bước 1: Mở cubeMX tạo project chọn chip STM32F103C8Tx
Bước 2: Setup các chân input/ouput, thông số phù hợp với yêu cầu project trong
mục: Pinout & Configuration
Như mình đang setup cho project bật tắt led.
11
Bước 3: Lựa chọn chế độ, bộ giao động thạch anh ngoài ở mục: Clock
Configuration
12
Bươcs 4: Đặt tên, địa chỉ lưu project, biên dịch sinh code đến Keilc V5
13
Bước 5: Nhấn Generate code : để sinh code sang KeilC V5
Bước 6: Mở KeilC thư mục chứa code sinh từ cube :
Bước 7: Vào file main.c tại Application/User/Core
14
Bước 8: Code bật tắt led tại file main.c trong hàm while () và biên dịch (F7) thành
công
15
PHẦN 2. LẬP TRÌNH ADC/DAC
2.1. Lập trình ADC(Analog to Digital Converter)
2.1.1. Lý thuyết về ADC
Hiện nay, hầu hết các dòng vi điều khiển đều được tích hợp khối ngoại vi chuyển
đổi tín hiệu tương tự – số (ADC). Đây là một bộ phận quan trọng giúp vi điều
khiển có thể đọc được với các tín hiệu analog từ bên ngồi như tín hiệu của các
cảm biến loại analog trả về (cảm biến nhiệt độ, độ ẩm, biến trở, quang trở…).
những chức năng chính của khối adc:
Các đầu vào: Vi điều khiển STM32F411 được tích hợp bộ chuyển đổi ADC 12bit
loại SAR. Bộ chuyển đổi này cho phép lựa chọn 1 trong 19 kênh đầu vào, trong đó
có 16 kênh đầu vào ngoại (là các chân vi điều khiển) và 3 kênh đầu vào nội là điện
áp nguồn cung cấp cho vi điều khiển, cảm biến nhiệt độ được tích hợp sẵn của vi
điều khiển và một kênh đo điện áp chân V_BAT. Các kênh đầu vào này có thể chia
làm 2 nhóm chuyển đổi: regular (thơng thường) hoặc injected (chèn vào khi 1 ADC
khác đang chuyển đổi)
Độ phân giải: Cho phép cấu hình độ phân giải: 12bit, 10bit, 8bit hoặc 6bit. Kết quả
chuyển đổi của khối ADC sẽ được lưu trữ trong 16bit thấp của 1 thanh ghi, người
dùng có thể lựa chọn lưu ở phần bit thấp hoặc bit cao. Kết quả này tương ứng với
dải điện áp đầu vào của mỗi channel, và điện áp đầu vào phải nằm trong khoảng
Vref- <= Vin <= Vref+, với Vref- và Vref+ có thể thiết kế được.
– Vref- là điện áp tham chiếu dưới, thường sử dụng VSSA = VSS (GND), khi giá
16
trị điện áp đầu vào ADC nhỏ hơn hoặc bằng Vref- thì giá trị kết quả chuyển đổi là
0;
– Vref+ là điện áp tham chiếu trên, thường sử dụng VDDA = VDD(VCC), khi giá
trị điện áp đầu vào ADC lớn hơn hoặc bằng Vref+ thì giá trị kết quả chuyển đổi sẽ
là tối đa của số bit độ phân giải.
Các chế độ chuyển đổi: Quá trình chuyển đổi ADC của các kênh có thể được lựa
chọn thực hiện theo các chế độ sau:
– Single Channel, single conversion mode – Chế độ chuyển đổi đơn kênh, chuyển
đổi 1 lần: Ở chế độ này, kênh đầu vào được lựa chọn sẽ được thực hiện chuyển đổi
một lần, kết quả được lưu vào thanh ghi kết quả (ADC_DR), cờ báo kết thúc quá
trình chuyển được được bật lên, yêu cầu ngắt sẽ được sinh ra nếu người dùng cấu
hình cho phép ngắt.
– Multichannel (scan), single conversion – Chế độ chuyển đổi nhiều kênh, chuyển
đổi 1 lần: Ở chế độ này, bộ ADC sẽ lần lượt chuyển đổi một chuỗi các kênh đầu
vào đã được cấu hình từ trước, tối đa có thể chuyển đổi được 16 kênh. kết quả
chuyển đổi của kênh cuối cùng sẽ được lưu vào thanh ghi ADC_DR, cờ báo kết
thúc quá trình chuyển được được bật lên, yêu cầu ngắt sẽ được sinh ra nếu người
dùng cấu hình cho phép ngắt. Chế độ này cần được kết hợp với tính năng DMA để
có thể nhận đầy đủ kết quả chuyển đổi của các kênh.
Thứ tự chuyển đổi của các kênh có thể được người dùng sắp xếp và thời gian lấy
mẫu của các kênh có thể được cấu hình độc lập.
*Tính năng DMA (Direct Memory Access) hỗ trợ ngoại vi có thể chuyển dữ liệu
trực tiếp đến bộ nhớ mà không cần sự can thiệp của CPU.
17
– Single-channel continuous conversion mode – Chế độ chuyển đổi đơn kênh,
chuyển đổi liên tục: Ở chế độ này kênh được chọn sẽ được chuyển đổi liên tục mà
không cần sự can thiệp của CPU trong mỗi lần chuyển đổi. Chức năng DMA với
mode circular nên được sử dụng trong chế độ này để giảm tải cho CPU.
– Multichannel (scan) continuous conversion mode – Chế đội chuyển đổi nhiều
kênh, chuyển đổi liên tục: Ở chế độ này các kênh được chọn sẽ được chuyển đổi
liên tục mà không cần sự can thiệp của CPU trong mỗi lần chuyển đổi. Chức năng
18
DMA với mode circular kết hợp với việc tăng bộ nhớ tự động nên được sử dụng
trong chế độ này để giảm tải cho CPU.
– Injected conversion mode – Chế độ chèn: Chế độ này được thiết kế để bộ ADC
có thể chuyển đổi ngay tức thì channel đã được cấu hình hoạt động ở chế độ này.
Nhóm kênh Injected có độ ưu tiên hơn nhóm kênh Regular nên nó có thể làm gián
đoạn q trình chuyển đổi của kênh thơng thường.
– Analog watchdog -giám sát kết quả analog: Tính năng này cho phép tạo ngắt khi
giá trị analog ra khỏi ngưỡng cho phép. Khi kết quả chuyển đổi ADC của điện áp
đầu vào bé hơn ngưỡng dưới (LTR) hoặc lớn hơn ngưỡng trên (HTR) thì bit trạng
19
thái báo hiệu vượt ngưỡng được bật lên và yêu cầu ngắt có thể được tạo ra nếu
người lập trình cấu hình cho phép ngắt. Giá trị LTR và HTR cũng được người dùng
cấu hình thơng qua các thanh ghi.
Các tín hiệu kích hoạt bộ ADC bắt đầu chuyển đổi có thể là lệnh từ phần mềm để
bật bit enable hoặc từ các ngoại vi khác như các bộ Timer hoặc ngắt ngoài ở line
11,15.
MỘT SỐ THANH GHI CỦA KHỐI ADC
Một số thanh ghi của khối ADC mà các bạn nên quan tâm để hỗ trợ cho việc debug
hoặc can thiệp vào thư viện, lập trình ở mức thấp hơn
ADC_SR – Thanh ghi chứa các bit trạng thái của khối ADC:
20
– OVR: Overrun
– STRT: Regular channel start flag
– JSTRT Injected channel start flag
– JEOC: Injected channel end of conversion
– EOC: Regular channel end of conversion
– AWD: Analog watchdog flag
ADC_DR – Thanh ghi kết quả chuyển đổi ADC dành cho các kênh chuyển đổi
thơng thường, thanh ghi này có 32bit, tuy nhiên có 16bit thấp được sử dụng để lưu
trữ kết quả chuyển đổi ADC, và kết quả có thể được lựa chọn ở phần thấp hoặc cao
của 16bit này. (Tương tự như ADC_DR thì có các thanh ghi ADC_JDRx (x=1..4)
để lưu kết quả chuyển đổi các Injected channel)
2.1.2. Thực hành 1 – adc đơn kênh, chuyển đổi 1 lần sử dụng chế độ polling
Bài thực hành này sẽ sử dụng phần mềm STM32CUBEMX để cấu hình ADC
channel 0 (Chân PA0) hoạt động với chế động Single channel – Continuous
conversion mode. Giá trị ADC sẽ được xem thông qua giao diện debug.
21
Bước 1: Kích chọn dịng STM32F411VETx và sau đó chọn “Start Project”.
Bước 2: Chọn Serial Wire để nạp code
Bước 3: Click chuột phải vào chân PA0 sau đó tích vào ô ADC1_IN0
22
Bước 4: Chỉnh các thông số ADC của chân PA0
Chọn clock cho bộ Prescaler = PCLK2/2 = 16/2 = 8 MHz, độ phân giải = 12 bits.
Data Alignment = Right alignment: Dữ liệu sẽ được ghi vào phần thấp của thanh
ghi ADC_DR
Vì bài viết này hướng dẫn các bạn đọc ADC ở chế độ đơn kênh, đọc liên tục
nên Scan Conversion Mode sẽ bị Disabled còn Continuous Conversion
Mode được Enabled. Các thơng số cịn lại giữ ngun chế độ mặc định.
23
Lưu ý: Các bạn có thể thay đổi thứ tự lấy mẫu của các kênh ADC (đối với chuyển
đổi ADC đa kênh) hoặc thời gian lấy mẫu ở mục ADC_Regular_ConversionMode
-> Rank -> Channel/Sampling Time. Tùy vào ứng dụng mà chúng ta có thể chọn
thời gian lấy mẫu cho phù hợp.
Bước 5: Setting project và sinh code
Bước 6: Click chọn Open Project và chuyển qua tab Keil C.
24
Mở file main.c, tại mục /* USER CODE BEGIN PV */ ta khai báo biến value_adc
để lưu giá trị ADC đọc được. Vì giá trị ADC mà ta đọc được có 12 bits nên
biến value_adc có kiểu dữ liệu là uint16_t (số nguyên không dấu 16 bits)
Bước 7: Thực hiện project đọc giá trị ADC tại chân PA0, một giây lấy giá trị một
lần và dùng debug để quan sát giá trị của biến value_adc.
Ở file main.c, ta gọi hàm HAL_ADC_Start để bắt đầu q trình chuyển đổi ADC.
Thơng số truyền vào cho hàm này là địa chỉ của bộ ADC mà chúng ta đang sử
dụng (hadc1)
25