Khi sử dụng phần mềm sinh code ta sẽ được phần code như bên dưới. Khi viết chương trình ứng dụng ta sẽ viết các phần vào đúng vị trí comment dành riêng cho nó để khi chinh sửa file cấu hình port.ioc và sinh code lại thì những phần code đó sẽ không bị xóa mất. Sau đây là các mục comment tương ứng với các phần code.
Phần khai báo thư viện /* USER CODE BEGIN Includes */
Phần khai báo define và macro /* USER CODE BEGIN PM */
Phần khai báo biến /* USER CODE BEGIN PV */
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 53 Phần chương trình trước vòng lặp while (1) /* USER CODE BEGIN 2 */
Phần trương trình trong vòng lặp while (1) /* USER CODE BEGIN 3 */
Trong các bài thực hành sẽ chỉ nêu nhưng đoạn code chính để phần trình bày được ngắn gọn và tránh lặp lại, chúng ta phải viết lại bằng cách thêm những đoạn code chính này vào đúng các mục comment dành cho nó.
/* USER CODE BEGIN Header */ /**
************************************************************** * @file : main.c
* @brief : Main program body
************************************************************* * @attention
*
* <h2><center>© Copyright (c) 2020 STMicroelectronics. * All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause *
******************************************* */
/* USER CODE END Header */
/* Includes ---*/
#include "main.h"
/* Private includes ---*/ /* USER CODE BEGIN Includes */
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 54
/* USER CODE END Includes */
/* Private typedef ---*/ /* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ---*/ /* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro ---*/ /* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes ---*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---*/ /* USER CODE BEGIN 0 */
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 55
/**
* @brief The application entry point. * @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration---*/
/* Reset of all peripherals, Initializes the Flash interface and
the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 56 {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration * @retval None
*/
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 336; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 57 Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType =
RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { Error_Handler(); } } /**
* @brief GPIO Initialization Function * @param None
* @retval None */
static void MX_GPIO_Init(void) {
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 58
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence. * @retval None
*/
void Error_Handler(void) {
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error
return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred. * @param file: pointer to the source file name
* @param line: assert_param error line source number * @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name
and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 59
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
4.2.HÌNH XUNG CLOCK CHO VI ĐIỀU KHIỂN
Trong các nguồn dao động cung cấp cho STM32 hoạt động bao gồm có : High Speed Internal (HSI : Xung nội tốc độ cao) và High Speed External (HSE : Xung ngoại tốc độ cao).Có nhiều lý do ta sẽ sử dung xung ngoại thay cho xung nội như khi thạch anh ngoài có thể cung cấp dao động cao hơn nguồn xung nội, giúp thu được số lieu chính xác hơn khi giao tiếp với ngoại vi đo nhiệt độ cao hơn rất nhiều so với 25 độ C. Hay như trong một vài trường hợp phải giao tiếp với ngoại vi chỉ có thể hoạt động ở một tần số xác định.
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 60 Bên cạnh nguồn xung tốc độ cao ta còn có Low Speed External (LSE: xung ngoại tốc độ thấp) và Low Speed Internal (LSI: xung nội tốc độ thấp) để điều khiển ngoại vi Real Time Clock (RTC) và Independent Watchdog (IWDT).
Một mạng lưới phức tạp chịu trách nhiệm truyền tín hiệu dao động bên trong STM32 được gọi là Clock Tree. Clock tree sử dung nhiều bộ Phase-Locked Loops (PLL) và Prescalers để tăng / giảm tần số nguồn khi cần thiết.
Lý do chúng ta cần nhiều bộ chia tần số nguồn là để đảm bảo khả năng hoạt động cũng như giảm thiểu năng lượng tiêu thụ ở những chức năng không cần thiết [1].
Cấu hình ClockTree sẽ được thực hiện qua một thiết bị ngoại vi có tên là Reset and Clock Control (RCC) số 2 Hình 4. 11, và nó sẽ đựợc thực hiện qua các bước:
Bước 1: Cấu hình chân dao động cho vi điều khiển.
Trong cửa sổ Pinout & Configuration hình 4. 11, chọn System Core (số 1). Chọn mục RCC (số 2). Trong mục High Speed Clock (HSE), chọn Crystal/Ceramic Resonator (số 3), để lấy xung dao động từ thạch anh 8MHz gắn trên board STM32VE qua 2 chân PH0 và PH1 (số 4).
Hình 4.12:Cấu hình Clock cho vi điều khiển
Bước 2: Cấu hình Clock.
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 61 Số 1: Chọn ngoại tốc độ cao HSE.
Số 2: Chọn tần số thạch anh 8Mhz. Số 3: Chọn bộ chia 8.
Số 4: Chọn bộ nhân 336
Số 5: Chọn PLLCLK để tăng tần số
Số 6: Kết quả sau khi chọn PLLCLK là 168Mhz (tần số tối đa của vi điều khiển) Số 7: Chọn bộ chia 4 cho bus ABH1
Số 8: Chọn bộ chia 4 cho bus ABH2
Sau khi đã cấu hình xong và sinh code tự động ta sẽ được 1 đoạn code cấu hình Clock cho hệ thống như hình 4.13.
Như vậy chúng ta đã cấu hình xong phần Clock dao động cho toàn bộ hệ thống, về sau chúng ta sẽ sử dụng lại file.ioc này và tùy chỉnh thêm cho các module khác như GPIO, ADC, I2C,.. của vi điều khiển. Vì vậy, phần cấu hình xung clock sẽ không đề cập lại trong các bài thực hành và chương trình main.
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 62
4.3.ĐIỀU KHIỂN LED ĐƠN 4.3.1.Sơ đồ phần cứng
Mạch điện giao tiếp vi điều khiển với module led 8 đơn như hình 5.14
Hình 4.14:Sơ đồ nguyên lý giao tiếp vi điều khiển với module 8 led đơn
4.3.2.Cấu hình chân cho vi điều khiển
Module 8 LED đơn giao tiếp trực tiếp với 8 chân của vi điều khiển từ PA0 đến PA7. Cấu hình port trong CubeMX được minh họa như Hình 4.15.
Phần đánh số 1 là chọn chức năng GPIO_Output cho chân PA7, tương tự cho các chân PA0 đến chân PA6.
Phần đánh số 2 chọn mục GPIO để cấu hình chi tiết cho từng chân. Phần đánh số 3 chọn các mục Parameter Setting như trong Hình 4.15.
Vì đã cấu hình xung clock cho hệ thống ở phần trước nên ta không cấu hình lại các thông số trong mục Clock Configuration nữa.
Sau khi cấu hình xong trong CubeMX ta nhấn Ctrl + S để sinh code tự động. Hình 4.16 là phần code được sinh ra trong chương trình main tương ứng với các mục đã chọn trong CubeMX.
Khi viết 1 chương trình ứng dụng trong file main.c ta không cần khai báo lại cấu hình chân. Và để đơn giản trong việc trình bày code sinh viên thực hiện đề tài chỉ nêu các dòng code chính mà bỏ qua việc trình bày lại phần cấu hình chân cho vi điều khiển.
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 63
Hình 4.15:Cấu hình port cho 8 led đơn trong CubeMX
Hình 4.16:Phần code được sinh ra từ CubeMX
4.3.3.Các hàm sử dụng
Hàm thứ 301: là hàm xuất dữ liệu 1 byte ra module 8 led đơn
void xuat_8led_1byte(uint8_t byte) {
GPIOA->ODR = byte;
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 64 Hàm này có chức năng xuất 1 byte dữ liệu ra module 8 led. Thanh ghi ODR có chưng năng xuất dữ liệu trực tiếp ra các port GPIO.
Hàm thứ 302: là hàm xuất dữ liệu 2 16 bit ra module 32 led đơn
void xuat_8led_2x4bit(uint8_t YH,uint8_t YL) {
uint8_t YHL;
YH=(YH<<4)&0x00f0; YL=YL&0x000f; YHL=YH|YL;
GPIOA->ODR = YHL;
}
Hàm này có chức năng xuất 4bit cao và 4 bit thấp ra module 8 led.
Các hàm này được lưu trong file thư viện TV_DATN_1.c và TV_DATN_1.h
Khi sử dụng thư viện này ta tiến hành copy TV_DATN_1.c vào thư mục Src và copy TV_DATN_1.h và thư mục Inc của Project.
4.3.4.Bài tập mẫu
Phần này thực hành các bài điều khiển led dùng vòng lặp for, các chương trình đơn giản dễ hiểu.
a. Mục đích: biết cách viết chương trình điều khiển led đơn chớp tắt. b. Lưu đồ và giải thích lưu đồ:
Tiến hành xuất dữ liệu của biến Y ra led đơn và dữ liệu 8 bit 0 sẽ làm 8 led tắt. Gọi hàm delay với thời gian tùy ý. Đảo biến y đang là 8 bit 0 thì sẽ trở thành 8 bit 1 hay 0xFF, quay trở lại xuất dữ liệu của biến y ra led đơn và làm 8 led sáng. Sau đó 3 công việc này được lặp đi lặp lại vô điều kiện nên trong lưu đồ không có ký hiệu kết thúc end.
Bài mẫu 101. Chương trình điều khiển 8 LED chớp tắt. Lưu tên file là “mau_101_choptat_8LED”.
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 65
Hình 4.17:Lưu đồ điều khiển 8 led chớp tắt
c. Chương trình:
#include "main.h" #include "TV_DATN_1.h"
uint8_t y;
int main(void)
{ y=0; while (1) { xuat_8led_1byte(y); HAL_Delay(200); y=~y; } }
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 66 e. Quan sát kết quả: nếu kết quả không đúng yêu cầu thì kiểm tra lại chương trình.
f. Giải thích chương trình:
Lệnh “uint8_t y;”: khai báo biến y là 8 bit không dấu.
Lệnh “Y=0;”: có chức năng gán dữ liệu cho biến y bằng 0 để điều khiển 8 led tắt. Lệnh “WHILE(TRUE)”: có chức năng thực hiện các lệnh trong vòng lặp vô tận Lệnh “xuat_8led_1byte(y)”: có chức năng xuất 1 byte dữ liệu ra 8 led, hàm này viết sẵn trong thư viện khai báo: "TV_DATN_1.c"
Lệnh “HAL_Delay(200);” có chức năng delay để nhìn thấy led sáng hoặc tắt. Lệnh “y = ~ y;”: có chức năng đảo dữ liệu của biến y từ 00 thành FF để điều khiển led sáng.
Vòng lặp while thực hiện lại từ đầu.
Phần này thực hành các bài điều khiển led dùng vòng lặp for, các chương trình đơn giản dễ hiểu.
a. Mục đích: biết cách viết chương trình điều khiển 8 led sáng dần và tắt dần phải sang trái.
b. Lưu đồ và giải thích lưu đồ:
Tiến hành xuất dữ liệu của biến Y ra led đơn và dữ liệu 8 bit 0 sẽ làm 8 led tắt, gọi hàm delay với thời gian tùy ý, dịch mức 1 vào bên phải của biến Y, tăng biến đếm I, kiểm tra xem bằng 8 hay chưa. Nếu chưa bằng quay trở lại xuất dữ liệu của biến Y ra led đơn sẽ làm 1 led sáng.
Tương tự như vậy sau 8 lần thì 8 led sáng dần lên từ phải sang trái và khi đó biến đếm I bằng 8 thì vòng lặp thứ nhất kết thúc.
Công việc cũng thực hiện tương tự như vòng lặp thứ 2 nhưng dữ liệu dịch vào là mức 0 sẽ làm 8 led tắt dần từ phải sang trái.
Sau 8 lần thì vòng lặp thứ 2 cũng kết thúc và quay trở lại vòng lặp thứ nhất làm lại và cứ thế làm mãi.
Bài mẫu 102. Chương trình điều khiển 8 LED sáng dần và tắt dần phải sang trái.
BỘ MÔN ĐIỆN TỬ CÔNG NGHIỆP – Y SINH 67
Hình 4.18:Lưu đồ điều khiển 8 led sáng tắt dần
c. Chương trình:
#include "main.h" #include "TV_DATN_1.c"