You are on page 1of 15

TRƯỜNG ĐẠI HỌC KỸ THUẬT- CÔNG NGHỆ CẦN THƠ

KHOA KỸ THUẬT CƠ KHÍ


------

BÁO CÁO THỰC HÀNH VI ĐIỀU

GIẢNG VIÊN HƯỚNG DẪN SINH VIÊN THỰC HIỆN


Phạm Nguyễn Bá Nghiệp
2100501

Cần thơ, Tháng 12 năm 2023


Đề 4

Đề 4: Viết chương trình đọc giá trị biến trở P1 (với 100% biến trở là max tốc độ) ở
PIC1 và hiển thị giá trị phần trăm của biến trở lên LCD1 ở dòng thứ nhất, sau đó
truyền giá trị đó qua PIC2. Tại PIC2 viết chương trình nhận giá trị từ PIC1, sử dụng giá
trị được nhận điều khiển tốc độ động cơ tương ứng thông qua mô đun L298. Ở LCD2
của PIC2 hiển thị giá trị phần trăm của biến trở ở dòng thứ nhất. Giao thức truyền
thông là UART. Ví dụ: LCD1 ở PIC1 và LCD2 ở PIC2 hiển thị như ở đề 2.

Code và giải thích: Được lập trình trên MPLAB X IDE

1/ CODE TRUYỀN DATA

Các tệp đầu vào và đầu ra cần thiết cho các thao tác nhập và xuất, các thư viện
(stdio.h và stdlib.h), tệp đặc biệt của trình biên dịch XC8 (xc.h), và hai tệp đầu ra
tùy chỉnh (uart.h và lcd.h). Các tệp tùy chỉnh này có lẽ chứa các hàm mẫu và khai
báo cho các chức năng UART và LCD.

//

Định nghĩa tần số dao động _XTAL_FREQ là 8 MHz.


//

MAX_ADC_VALUE được đặt là 1023


//

Định nghĩa các chân điều khiển một màn hình LCD. Tương ứng với các chân của
thanh ghi D (RD) trên vi điều khiển PIC.
- “RS”: Là chân điều khiển (Register Select) của màn hình LCD, được định
nghĩa là chân RD2 của thanh ghi D.
- “EN”: Là chân kích hoạt (Enable) của màn hình LCD, được định nghĩa là
chân RD3 của thanh ghi D.
- “D4”, “D5”, “D6”, “D7”: Là các chân dữ liệu của màn hình LCD, tương ứng
với các chân RD4, RD5, RD6, và RD7 của thanh ghi D.

//
Đặt các bit cấu hình cho vi điều khiển. Vi điều khiển được cấu hình để sử dụng dao
động tốc độ cao (HS), với một số tính năng nhất định như bộ đếm Watchdog Timer
(WDTE), bộ đếm thời gian khởi động (PWRTE) và lập trình áp thấp (LVP) đã tắt.
- “FOSC”: Kiểu dao động là "High-Speed Crystal Oscillator" (HS), có nghĩa vi
điều khiển sử dụng dao động tinh thể tốc độ cao.
- “WDTE”: Watchdog Timer nó đã được tắt (OFF). Watchdog Timer thường
được sử dụng để kiểm soát việc chương trình có đang chạy đúng cách hay
không.
- “PWRTE”: Power-Up Timer đã được tắt (OFF). Power-Up Timer giúp đảm
bảo rằng vi điều khiển đã được cung cấp đủ thời gian để khởi động trước khi
bắt đầu thực hiện chương trình.

- “BOREN”: Brown-out Reset đã được bật (ON). Brown-out Reset là một chức
năng bảo vệ, nó đảm bảo rằng nếu mức điện áp nguồn xuống đến mức an
toàn, thì vi điều khiển sẽ được đặt lại để tránh hoạt động không ổn định.

- “LVP”: Chọn bật hoặc tắt Low-Voltage Programming (lập trình áp thấp),
Trong code nó đã được tắt (OFF). Lập trình áp thấp là một tính năng cho phép
lập trình vi điều khiển với mức điện áp thấp hơn.

- “CPD”: Chọn bật hoặc tắt Code Protection for Data Memory (bảo vệ mã
nguồn cho bộ nhớ dữ liệu). Trong dòng code thì Code Protection for Data
Memory đã được tắt (OFF), cho phép đọc và ghi vào bộ nhớ dữ liệu.

- “WRT”: Chọn bật hoặc tắt Flash Program Memory Write Enable (cho phép
ghi vào bộ nhớ chương trình Flash). Trường hợp này, nó đã được tắt (OFF),
ngăn chặn việc ghi vào bộ nhớ chương trình Flash.
- “CP”: Chọn bật hoặc tắt Code Protection for Program Memory (bảo vệ mã
nguồn cho bộ nhớ chương trình). Trong trường hợp CP đã được tắt (OFF),
cho phép đọc và ghi vào bộ nhớ chương trình.
//

- void initializeADC(void); initializeADC được khai báo kiểu void và không


có tham số. Hàm này được sử dụng để khởi tạo module ADC (Analog-to-
Digital Converter) trên vi điều khiển.
- unsigned int readADC(void); readADC được khai báo kiểu unsigned int và
không có tham số. Hàm này được sử dụng để đọc giá trị đo được từ module
ADC.
- unsigned int adcValue = 0; adcValue được khai báo kiểu unsigned int và
được gán giá trị ban đầu là 0.

//

- void main(void): là hàm chính (main function) của chương trình


- initializeADC(); Gọi hàm initializeADC để thực hiện các bước cần thiết để
khởi tạo và cấu hình module ADC. chứa các cài đặt như chọn nguồn clock
cho ADC, cấu hình chân ADC.
- char lcdString[20]; Khai báo một mảng ký tự (char) có tên là lcdString với
kích thước 20. Được sử dụng để lưu trữ thông điệp hoặc dữ liệu hiển thị lên
một màn hình LCD.
- TRISD = 0x00; Đặt tất cả các chân trên PORTD là đầu ra. Sử dụng để kết nối
với một màn hình LCD.
- RA0 = 1; Đặt chân RA0 (pin A0) làm đầu vào. Đọc dữ liệu từ DC.
- TRISA0 = 1; Đặt chân RA0 làm đầu vào (input). Điều này đảm bảo rằng
chân RA0 được cấu hình đúng trước khi đọc giá trị từ nó.
- Lcd_Init(); Gọi hàm Lcd_Init() để khởi tạo màn hình LCD.
- UART1_Init(9600); Gọi hàm UART1_Init(9600) để khởi tạo module UART
(Giao tiếp dạng chuỗi) với tốc độ truyền là 9600 bit mỗi giây.

//

- while(1) thực hiện việc đọc giá trị từ ADC, chuyển đổi thành phần trăm, gửi
qua UART, và hiển thị trên màn hình LCD theo chu kỳ với độ trễ.
- adcValue = readADC(); Gọi hàm readADC() để đọc giá trị từ module ADC
và lưu vào biến adcValue.
- float percentage = ((float)adcValue / MAX_ADC_VALUE) * 100.0;
Chuyển đổi giá trị ADC thành phần trăm và lưu vào biến percentage. Giá trị
phần trăm được tính bằng cách chia giá trị ADC cho giá trị tối đa
(MAX_ADC_VALUE) và nhân với 100.
- UART_sendChar((char)percentage); Gửi giá trị phần trăm thông qua
UART. Hàm UART_sendChar() được sử dụng để gửi một ký tự thông qua kết
nối UART.
- delay_ms(100); Tạo độ trễ 100 milliseconds.
- sprintf(lcdString, "Tocdo = %0.1f ", percentage); Tạo một chuỗi ký tự
(lcdString) chứa thông điệp để hiển thị trên màn hình LCD. Chuỗi này bao
gồm nội dung "Tocdo = " và giá trị phần trăm với độ chính xác 0.1.
- Lcd_Set_Cursor(1, 1); Đặt vị trí con trỏ trên màn hình LCD tại dòng 1, cột
1.
- Lcd_Write_String(lcdString); Hiển thị chuỗi lcdString lên màn hình LCD.
- Lcd_Write_Char(223); Hiển thị biểu tượng độ (°) lên màn hình LCD.
- Lcd_Write_String("%"); Hiển thị ký tự '%' lên màn hình LCD, kết thúc
thông điệp hiển thị.

//
- Hàm initializeADC được sử dụng để cấu hình và khởi tạo module Analog-to-
Digital Converter (ADC)
- ADCON1bits.ADCS2 = 0; ADCON0bits.ADCS1 = 0;
ADCON0bits.ADCS0 = 1; Cài đặt nguồn clock cho ADC. Đây là Fosc/8. Ba
bit này xác định tần số của nguồn clock được sử dụng cho quá trình chuyển
đổi ADC.
- ADCON0bits.CHS2 = 0; ADCON0bits.CHS1 = 0; ADCON0bits.CHS0 =
0; Chọn kênh ADC. Trong đoạn mã này, kênh được chọn là AN0 (pin RA0).
Các bit này xác định kênh nào sẽ được đọc dữ liệu ADC.
- ADCON1bits.ADFM = 1; Đặt kết quả của quá trình chuyển đổi ADC là
chuẩn phải. Dữ liệu sẽ được đặt trong 10 bit thấp nhất của thanh ghi
ADRESH.
- ADCON1bits.PCFG3 = 1; ADCON1bits.PCFG2 = 1;
ADCON1bits.PCFG1 = 1; ADCON1bits.PCFG0 = 0; Cấu hình các chân
input analog thành digital. Tất cả các chân analog đều được cấu hình là
digital, nghĩa là có thể sử dụng cho các chức năng khác.
- ADCON0bits.ADON = 1; Bật ADC module. Bit này cần được thiết lập để
kích hoạt ADC và cho phép nó thực hiện quá trình chuyển đổi.

//

- unsigned int tempValue = 0; Khai báo biến tempValue để lưu giá trị đọc từ
ADC.
- ADCON0bits.GO_nDONE = 1; Thiết lập bit GO_nDONE trong thanh ghi
ADCON0 là 1 để bắt đầu quá trình chuyển đổi ADC. Khi bit này được set,
quá trình chuyển đổi ADC bắt đầu.
- while (ADCON0bits.GO_nDONE); Vòng lặp while đợi cho đến khi quá
trình chuyển đổi ADC hoàn thành. Bit GO_nDONE sẽ trở về 0 khi quá trình
chuyển đổi kết thúc.
- tempValue = ADRESH * 256 + ADRESL; Khi quá trình chuyển đổi kết
thúc, giá trị ADC được đọc từ thanh ghi ADRESH (byte cao) và ADRESL
(byte thấp). Để có giá trị ADC đầy đủ 10-bit, giá trị này được tính bằng cách
kết hợp byte cao và byte thấp thành một giá trị 16-bit.
- return tempValue; Trả về giá trị ADC đã đọc. Hàm này sẽ trả về giá trị
analog đại diện bởi kênh ADC đã chọn trong hàm initializeADC.

2/ CODE NHẬN DATA

Các tệp đầu vào và đầu ra cần thiết cho các thao tác nhập và xuất, các thư viện
(stdio.h và stdlib.h), tệp đặc biệt của trình biên dịch XC8 (xc.h), và hai tệp đầu ra
tùy chỉnh (uart.h và lcd.h). Các tệp tùy chỉnh này có lẽ chứa các hàm mẫu và khai
báo cho các chức năng UART và LCD.

//

Định nghĩa tần số dao động _XTAL_FREQ là 20 MHz.

//

MAX_ADC_VALUE được đặt là 1023


Tạo ra một hằng số có tên là TMR2PRESCALE với giá trị là 4.

Định nghĩa các chân điều khiển một màn hình LCD. Tương ứng với các chân của
thanh ghi D (RD) trên vi điều khiển PIC.
- “RS”: Là chân điều khiển (Register Select) của màn hình LCD, được định
nghĩa là chân RD2 của thanh ghi D.
- “EN”: Là chân kích hoạt (Enable) của màn hình LCD, được định nghĩa là
chân RD3 của thanh ghi D.
- “D4”, “D5”, “D6”, “D7”: Là các chân dữ liệu của màn hình LCD, tương ứng
với các chân RD4, RD5, RD6, và RD7 của thanh ghi D.

//

Đặt các bit cấu hình cho vi điều khiển. Vi điều khiển được cấu hình để sử dụng dao
động tốc độ cao (HS), với một số tính năng nhất định như bộ đếm Watchdog Timer
(WDTE), bộ đếm thời gian khởi động (PWRTE) và lập trình áp thấp (LVP) đã tắt.
- “FOSC”: Kiểu dao động là "High-Speed Crystal Oscillator" (HS), có nghĩa vi
điều khiển sử dụng dao động tinh thể tốc độ cao.
- “WDTE”: Watchdog Timer nó đã được tắt (OFF). Watchdog Timer thường
được sử dụng để kiểm soát việc chương trình có đang chạy đúng cách hay
không.
- “PWRTE”: Power-Up Timer đã được tắt (OFF). Power-Up Timer giúp đảm
bảo rằng vi điều khiển đã được cung cấp đủ thời gian để khởi động trước khi
bắt đầu thực hiện chương trình.

- “BOREN”: Brown-out Reset đã được bật (ON). Brown-out Reset là một chức
năng bảo vệ, nó đảm bảo rằng nếu mức điện áp nguồn xuống đến mức an
toàn, thì vi điều khiển sẽ được đặt lại để tránh hoạt động không ổn định.

- “LVP”: Chọn bật hoặc tắt Low-Voltage Programming (lập trình áp thấp),
Trong code nó đã được tắt (OFF). Lập trình áp thấp là một tính năng cho phép
lập trình vi điều khiển với mức điện áp thấp hơn.

- “CPD”: Chọn bật hoặc tắt Code Protection for Data Memory (bảo vệ mã
nguồn cho bộ nhớ dữ liệu). Trong dòng code thì Code Protection for Data
Memory đã được tắt (OFF), cho phép đọc và ghi vào bộ nhớ dữ liệu.

- “WRT”: Chọn bật hoặc tắt Flash Program Memory Write Enable (cho phép
ghi vào bộ nhớ chương trình Flash). Trường hợp này, nó đã được tắt (OFF),
ngăn chặn việc ghi vào bộ nhớ chương trình Flash.

- “CP”: Chọn bật hoặc tắt Code Protection for Program Memory (bảo vệ mã
nguồn cho bộ nhớ chương trình). Trong trường hợp CP đã được tắt (OFF),
cho phép đọc và ghi vào bộ nhớ chương trình.
//

- long PWM_freq = 5000; Khai báo một biến có kiểu dữ liệu là long có tên là
PWM_freq và gán giá trị là 5000 Hz.
- void PWM_Initialize(); Khai báo hàm PWM_Initialize không có tham số
truyền vào và không trả về giá trị. Sử dụng để khởi tạo cấu hình cho chế độ
PWM.
- void PWM_Duty(unsigned int duty); Khai báo hàm PWM_Duty có một
tham số là duty kiểu unsigned int và không trả về giá trị. Sử dụng để đặt giá
trị cho PWM.

- PR2 = (_XTAL_FREQ / (PWM_freq * 4 * TMR2PRESCALE)) - 1; Đặt


giá trị cho thanh ghi PR2, là thanh ghi chứa giá trị tối đa của Timer2 trước khi
nó reset. Giá trị này được tính toán để đảm bảo tần suất PWM mong muốn.
- CCP1M3 = 1; CCP1M2 = 1; Cấu hình chế độ của module CCP1. Nó được
cấu hình để sử dụng chế độ PWM.
- T2CKPS0 = 1; T2CKPS1 = 0; Cấu hình bộ chia tần số cho Timer2. Được
cấu hình để có bộ chia tần số bằng 4.
- TMR2ON = 1; Bật Timer2. Khi bit này được set, Timer2 bắt đầu đếm.
- TRISC2 = 0; Cấu hình chân RC2 làm chân đầu ra PWM. Chân này sẽ được
sử dụng để xuất tín hiệu PWM.

//

- if(duty < 1023): Kiểm tra nếu giá trị duty (độ rộng xung) nhỏ hơn 1023. Điều
này đảm bảo rằng giá trị duty nằm trong phạm vi hợp lý và không vượt quá
giới hạn.
- duty = ((float)duty / 1023) * (_XTAL_FREQ / (PWM_freq *
TMR2PRESCALE)); Tính toán giá trị thực sự của độ rộng xung PWM dựa
trên duty cycle. Điều này được thực hiện bằng cách chia giá trị duty cho 1023
(giá trị tối đa), sau đó nhân với tần suất nguồn clock (_XTAL_FREQ) và bộ
chia tần số của Timer2 (TMR2PRESCALE).
- CCP1X = duty & 1; CCP1Y = duty & 2;: Đặt các bit CCP1X và CCP1Y
dựa trên giá trị của duty. Điều này được sử dụng để cấu hình PWM và đảm
bảo phù hợp với chế độ PWM cụ thể.
- CCPR1L = duty >> 2; Đặt giá trị của 8 bit cao nhất của thanh ghi CCPR1L
dựa trên giá trị của duty. Điều này làm cho giá trị của duty được đặt chính xác
trong thanh ghi PWM.

//

- unsigned int ADCvalue = 0; Khai báo biến ADCvalue để lưu giá trị đo được
từ ADC (Analog-to-Digital Converter).
- float f, data; Khai báo hai biến kiểu float là f và data.
- char s[20]; Khai báo một mảng ký tự để lưu chuỗi, được sử dụng cho việc
định dạng và hiển thị trên LCD.
- int c = 33; Khai báo một biến nguyên c và gán giá trị là 33.
- TRISD = 0x00; Cấu hình các chân trên PORTD là đầu ra.
- RA0 = 1; Đặt chân RA0 làm đầu vào.
- TRISA0 = 1; Cấu hình chân RA0 là đầu vào.
- Lcd_Init(); Khởi tạo LCD để sử dụng.
- UART1_Init(9600); Khởi tạo UART1 với tốc độ baud là 9600.
- PWM_Initialize(); Khởi tạo module PWM.
- while(1) { ... } Vòng lặp vô hạn để thực hiện các công việc trong nó.
- data = UART1_Read(); Đọc một giá trị từ UART1.
- unsigned int ADCvalue = (data / 100) * MAX_ADC_VALUE; Chuyển đổi
giá trị đọc từ UART thành giá trị ADC. Giả sử data là giá trị từ 0 đến 100, và
nó được chuyển đổi thành giá trị ADC tương ứng.
- PWM_Duty(ADCvalue); Đặt giá trị độ rộng xung PWM dựa trên giá trị
ADC.
- __delay_ms(50); Tạo một độ trễ 50 milliseconds.
- sprintf(s, "Tocdo = %g ", data): Định dạng chuỗi để hiển thị thông tin về
tốc độ.
- Lcd_Set_Cursor(1, 1); Đặt con trỏ của LCD ở dòng 1, cột 1.
- Lcd_Write_String(s); Hiển thị chuỗi đã định dạng lên LCD.
- Lcd_Write_Char(223); Hiển thị ký tự độ (°) lên LCD.
- Lcd_Write_String("%"); Hiển thị ký tự "%" lên LCD.

You might also like