Bài thực hành 1 với nội dung Lập trình điều khiển vào ra cho GPIO. giúp các bạn làm quen với phần mềm, sơ đồ chân và các lệnh điều khiển vào ra căn bản và những bài tập giúp các bạn luyện tập thành thạo.
Trang 1BÀI 1 LẬP TRÌNH ĐIỀU KHIỂN VÀO/ RA GPIO
1. Giới thiệu sơ đồ nguyên lý Kit ARM STM32F103C8T6
- Sơ đồ chân
Hình 1.1 Sơ đồ chân KIT STM32F103C8T6
- Khối Led đơn – PC13
Hình 1.2 Mạch Led đơn
- Muốn điều khiển Led sáng – xuất mức Logic 0, ngược lại Led tắt – Xuất mức Logic 1
- Khối nút nhấn lắp thêm, mắc như hình 1.2
Trang 2
Hình 1.2 Mạch nút nhấn
- Khi đọc nút nhấn cần thiết lập trở kéo lên bên trong chíp:
GPIO_InitStruct.Pull = GPIO_PULLUP;
2 Các hàm điều khiển hoạt động vào/ra
- Các hàm điều khiển hoạt động vào ra trong API HAL
• HAL_GPIO_ReadPin
• HAL_GPIO_WritePin
• HAL_GPIO_TogglePin
• HAL_GPIO_LockPin
• HAL_GPIO_EXTI_IRQHandler
• HAL_GPIO_EXTI_Callback
• HAL_GPIO_Init
• HAL_GPIO_DeInit
- Hàm đọc dữ liệu
- Hàm ghi dữ liệu
- Hàm đảo mức logic
104 C1
10K R1
+3.3V
PB1
GND
INPUT
Trang 3- Câu lệnh xuất dữ liệu theo PORT, ví dụ với PORT B:
GPIOB->ODR=0x0000;//PB0 ÷ PB15 mức logic 0
- Câu lệnh đọc dữ liệu theo PORT, ví dụ với PORT B:
X= GPIOB->IDR;
3 Thiết kế ứng dụng hoạt động vào/ra
3.1 Các bước lập trình với hoạt động vào ra sử dụng STM32CubeMX
Cấu hình cho xung nhịp hệ thống
Cho phép xung nhịp của các PORT GPIO
Thiết lập chiều của chân GPIO
Cấu hình cho các chân GPIO
Viết thuật toán điều khiển GPIO
- Cấu hình cho xung nhịp hệ thống :
o SystemClock_Config();
Ví dụ :
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
//Lựa chọn nguồn xung cho bộ tạo dao động
RCC_OscInitStruct.OscillatorType =
RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue =
RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{Error_Handler();}
//Thiết lập hệ số chia tần cho các ngoại vi
RCC_ClkInitStruct.ClockType =
RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct,
Trang 4FLASH_LATENCY_0) != HAL_OK)
{ Error_Handler();}
}
Cho phép xung nhịp của các PORT GPIO
o HAL_RCC_GPIOx_CLK_ENABLE();
o Ví dụ : HAL_RCC_GPIOB_CLK_ENABLE();//Cho phép PORTB
- Thiết lập chức năng của chân GPIO
GPIO_MODE_INPUT Input Floating Mode
GPIO_MODE_OUTPUT_PP Output Push Pull Mode
GPIO_MODE_OUTPUT_OD Output Open Drain Mode
GPIO_MODE_AF_PP Alternate Function Push Pull Mode
GPIO_MODE_AF_OD Alternate Function Open Drain Mode
GPIO_MODE_ANALOG Analog Mode
GPIO_MODE_IT_RISING External Interrupt Mode with Rising edge trigger detection
GPIO_MODE_IT_FALLING External Interrupt Mode with Falling edge trigger detection GPIO_MODE_IT_RISING_FALLING External Interrupt Mode with Rising/Falling edge trigger detection GPIO_MODE_EVT_RISING External Event Mode with Rising edge trigger detection
GPIO_MODE_IT_RISING_FALLING External Interrupt Mode with Rising/Falling edge trigger detection GPIO_MODE_EVT_RISING External Event Mode with Rising edge trigger detection
GPIO_MODE_EVT_FALLING External Event Mode with Falling edge trigger detection
GPIO_MODE_EVT_RISING_FALLING External Event Mode with Rising/Falling edge trigger detection
- Cấu hình chân GPIO :
+ Trở kéo
GPIO_NOPULL No Pull-up or Pull-down activation
GPIO_PULLUP Pull-up activation
GPIO_PULLDOWN Pull-down activation
+ Tốc độ
GPIO_SPEED_FREQ_LOW Low speed
GPIO_SPEED_FREQ_MEDIUM Medium speed
GPIO_SPEED_FREQ_HIGH High speed
- Cấu hình các chân GPIO – (thiết lập khi các chân GPIO có chiều vào):
Trang 5Ví dụ chân PA0:
GPIO_InitStruct.Pin = GPIO_PIN_0;//Chân 0
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;//Chiều vào GPIO_InitStruct.Pull = GPIO_PULLUP;//Trở kéo lên
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- Cấu hình các chân GPIO – (thiết lập khi các chân GPIO có chiều ra):
Ví dụ chân PB9:
GPIO_InitStruct.Pin = GPIO_PIN_9;//Chân 9
GPIO_InitStruct.Mode =
GPIO_MODE_OUTPUT_PP;//chiều ra PUSH PULL GPIO_InitStruct.Pull = GPIO_NOPULL;//Không kéo trở GPIO_InitStruct.Speed =
GPIO_SPEED_FREQ_LOW;//Tần số thấp HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
- Xuất dữ liệu
o HAL_GPIO_WritePin (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState) ;
o Hoặc : GPIOB->ODR=data;
Ví dụ: Xuất mức logic 1 trên chân PB9
- HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);
- hoặc: GPIOB->ODR=0x0200;//0b0000 0010 0000 0000
- Đảo mức tín hiệu
o HAL_GPIO_TogglePin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin);
Ví dụ: Đảo mức logic trên chân PA0
- HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_0);
- Nhập dữ liệu
o HAL_GPIO_ReadPin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
Ví dụ: Đọc dữ liệu trên chân PA0
Trang 6X = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
3.2 Khung chương trình lập trình hoạt động vào ra
#include "main.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
SystemClock_Config();
MX_GPIO_Init();
while (1)
{}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue =
RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{ Error_Handler();}
RCC_ClkInitStruct.ClockType =
RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct,
FLASH_LATENCY_0) != HAL_OK)
{ Error_Handler(); }
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = LED1_Pin|LED2_Pin|LED3_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
Trang 7HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void Error_Handler(void){ disable_irq();while (1){}}
#ifdef USE_FULL_ASSERT
#endif /* USE_FULL_ASSERT */
3.3 Ví dụ
Ví dụ 1: Lập trình điều khiển LED –(kết nối với chân PA0) sáng
#include "main.h"
int main(void)
{
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); }
}
Ví dụ 2: Lập trình điều khiển LED –(kết nối với chân PA0) nhấp nháy với chu kì 1s
#include "main.h"
int main(void)
{
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
Trang 8HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); HAL_Delay(500);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); HAL_Delay(500);
}
}
Ví dụ 3: Lập trình điều khiển khi nhấn nút Select (kết nối với chân PA11)
LED (kết nối với chân PA0) sáng, khi không nhấn LED tắt
#include "main.h"
int main(void)
{
SystemClock_Config();
MX_GPIO_Init();
while (1){
if(HAL_GPIO_ReadPin(GPIOA, GPIO_Pin_11)==0)
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
else
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
Trang 9RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType =
RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0,GPIO_PIN_RESET);
/*Configure GPIO pins : PA11*/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PA0*/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
Trang 10Ví dụ 4: Lập trình điều khiển mạch Led 7 thanh (A Chung) hiển thị lần lượt từ 0 đến 9 Mạch
điện như hình sau:
- Sử dụng mã Led 7 thanh từ 0 đến 9 bằng cách khai báo mảng:
char ma_led[]={0x00c0,0x00f9,0x00a4,0x00b0,0x0099,
0x0092,0x0082,0x00f8,0x0080,0x0090};
- Cách 01: Viết chương trình chuyển từ byte sang bit từ mảng ma_led[]sang từng chân
của Vi điều khiển kết nối với các thanh a,b,c,d,e,f,dp của Led 7 thanh
void hienthi_7seg(unsigned char data)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0, data&0x01);//a
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1, (data>>1)&0x01);//b
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2, (data>>2)&0x01);//c
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3, (data>>3)&0x01);//d
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4, (data>>4)&0x01);//e
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, (data>>5)&0x01);//f
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6, (data>>6)&0x01);//g
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7, (data>>7)&0x01);//dp
}
int dem;
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1)
Trang 11{
hienthi_7seg(ma_led[dem%10]);
HAL_Delay(1000);
dem++;
}
}
- Cách 02: Sử dụng câu lệnh GPIOB->ODR xuất dữ liệu
int dem;
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
GPIOB->ODR =ma_led[dem%10];
HAL_Delay(1000);
dem++;
}
}
Chú ý: Sinh viên cần cấu hình chiều ra dữ liệu trên các chân điều khiển Led 7 thanh
Ví dụ 5: Lập trình điều khiển mạch Led 7 thanh (A Chung) hiển thị một số có 2 chữ số
Mạch điện như hình sau:
- Sử dụng phương pháp quét led để điều khiển 2 Led 7 thanh:
- Cách 01: Viết chương trình chuyển từ byte sang bit từ mảng ma_led[]sang từng chân
của Vi điều khiển kết nối với các thanh a,b,c,d,e,f,dp của Led 7 thanh
Trang 12void hienthi_7seg(unsigned char data)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0, data&0x01);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1, (data>>1)&0x01);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2, (data>>2)&0x01);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3, (data>>3)&0x01);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4, (data>>4)&0x01);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, (data>>5)&0x01);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6, (data>>6)&0x01);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7, (data>>7)&0x01);
}
int dem;
int main(void)
{
HAL_Init();SystemClock_Config();MX_GPIO_Init();
dem=12;
while (1)
{
}
- Cách 02: Sử dụng câu lệnh GPIOB->ODR xuất dữ liệu
int dem;
int main(void)
{
HAL_Init();SystemClock_Config();MX_GPIO_Init();
dem=12;
while (1)
{
}}
Chú ý: Sinh viên cần cấu hình chiều ra dữ liệu trên các chân điều khiển Led 7 thanh
Trang 134 Bài tập: (Sinh viên tự chọn chân LED và KEY)
1 Viết chương tình hiển thị các LED chẵn và lẻ sáng nhấp nháy (LED 1,3,5,7 sáng, LED
2,4,6,8 Tắt và ngược lại)
2.Viết chương trình điều khiển 8 LED sáng tuần tự khi nhấn KEY1 các LED tắt
3 Viết chương trình điều khiển 8 LED theo quy luật Khi nhấn KEY1 một lần LED1 sáng
các LED khác tắt, nhấn KEY1 2 lần LED1, LED2 sáng các LED khác tắt… Nhấn KEY1 8 lần
cả 8 LED đều sáng
4 Viết chương trình điều khiển đếm số lần nhấn KEY2 và hiển thị số lần nhấn trên 4 LED
(LED4- LED8) dưới dạng số nhị phân (Giả thiết: số lần nhấn <=15)
5 Viết chương trình điều khiển đếm số lần nhấn KEY1 và hiển thị số lần nhấn trên 4 Led
7 thanh (0000 đến 9999)
Tham khảo mạch điện điều khiển Led 7 thanh bằng phương pháp quét