Giao tiếp GPIO STM8S - Control GPIO STM8S with IAR Compiler
Xin chào tất cả các bạn,
Bài viết hôm nay, mình sẽ hướng dẫn các bạn sử dụng tính năng đầu tiên và cũng là quan trọng nhất của vi điều khiển, đó là giao tiếp Input/Output (hay còn được gọi là GPIO - General Purpose Input/Output). Như các bạn cũng đã biết, mỗi loại vi điều khiển đều có tính năng này. GPIO thực chất là những chân của Vi điều khiển có khả năng xuất (output) và nhận dữ liệu (input), tính năng này giúp cho chúng có thể điều khiển, giao tiếp với các ngoại vi và truyền/nhận được dữ liệu.
Trong bài viết này, mình sẽ hướng dẫn các bạn cách cấu hình sử dụng các chân của STM8S để phục vụ cho chức năng Input và Output. Như Ở bài trước chúng ta đã tạo được project để lập trình bằng trình biên dịch IAR. Hôm nay, chúng ta sẽ sử dụng project này để tiến hành lập trình. Để bắt đầu học một cách tốt nhất, các bạn cần xem qua sơ đồ nguyên lý, cách kết nối chân của Board mình đang sử dụng và sau đó xem qua Datasheet của em nó để có thể nắm rõ được chức năng của từng chân vi điều khiển. Trong bài viết này, mình sử dụng Board STM8S103F3P6.
Nào tiến hành thôi!!!
ĐIỀU KHIỂN CÁC CHÂN STM8S VỚI CHỨC NĂNG OUTPUT
Trong ví dụ này, mình sẽ sử dụng Led có sẵn được kết nối với chân B5 trên Board STM8S103F3P6 để thực hành luôn nhé!
Đầu tiên, chúng ta tiến hành mở work space (Project) đã tạo từ bài trước (http://ratdongian.blogspot.com/2018/06/huong-dan-chi-tiet-tao-projects-lap.html) và sau đó tiến hành thêm thư viện stm8s_gpio.c để tiến hành lập trình (thư viện này tại đường dẫn: "..\Blink\STM8S_StdPeriph_Driver\src\stm8s_gpio.c"). Nếu chúng ta không thêm thư viện stm8s_gpio.c thì khi biên dịch chương trình sẽ xuất hiện lỗi: Error[Li005]: no definition for "GPIO_Init" và Error[Li005]: no definition for "GPIO_WriteReverse".
Sau khi thêm thư viện xong, chúng ta tiến hành click vào biểu tượng make trên thanh công cụ hoặc nhấn F7 để build project. Nếu xuất hiện lỗi: Fatal Error[Pe035]: #error directive: "Please select first the target STM8S/A device used in your application (in stm8s.h file)" thì các bạn tiến hành vào file stm8s.h và bỏ comment tại dòng mà vi điều khiển chúng ta đang dùng, thực hiện như hình dưới (ở bài viết này mình sử dụng STM8S103F3P6 nên mình sẽ uncomment dòng #define STM8S103). Nếu không xuất hiện lỗi nào, thì các bạn chuyển sang bước tiếp theo nhé :D
LẬP TRÌNH VÀ TÌM HIỂU THƯ VIỆN GPIO
Chúng ta quay lại file main.c để lập trình chương trình cho stm8s hoạt động. Đầu tiên trong file này, chúng ta cần thêm thư viện chuẩn stm8s.h bằng dòng lệnh: #include "stm8s.h"
Vì STM8S hoạt động tần số cao (16Mhz thạch anh nội - có thể cấu hình thạch anh ngoại) nên thời gian thực thi một lệnh của nó rất nhanh. Do đó, Để cho việc quan sát trạng thái Led(GPIO) được dễ dàng chúng ta cần một hàm Delay để làm trễ, đợi cho chúng ta có thể thấy được sự thay đổi của chúng. Thư viện chuẩn của STM8S (STM8S_StdPeriph_Driver) không hỗ trợ chúng ta chương trình Delay, nên chúng ta sẽ tạo một hàm delay bằng cách viết một đoạn chương trình:
Lưu ý: Chương trình Delay trên làm trễ thời gian không chính xác, chỉ nên dùng để Test trạng thái khi mới tiếp cận với chức năng GPIO này (dễ dàng quan sát trạng thái). Nếu cần độ chính xác hơn, thì ở bài sau, mình sẽ hướng dẫn các bạn sử dụng Timer để tạo hàm Delay.
Dưới đây là một số hàm mà thư viện stm8s_gpio hỗ trợ chúng ta trong quá trình lập trình (tham khảo thêm trong file thư viện stm8s_gpio.h và stm8s_gpio.c):
Tham số truyền vào: GPIOx với x là các port của STM8S (x tương ứng từ A -> I).
Ví dụ: Khởi tạo lại GPIO cho Port B => GPIO_DeInit(GPIOB);
Hàm: void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, GPIO_Mode_TypeDef GPIO_Mode);
Chứ cnăng: Khởi tạo GPIOx theo cấu hình (Input/Output)
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
- GPIO_Pin: Số thứ tự chân cần sử dụng trong Port lựa chọn (GPIO_PIN_0 đến GPIO_PIN_7, GPIO_PIN_LNIB, GPIO_PIN_HNIB, GPIO_PIN_ALL).
- GPIO_Mode: cài đặt chế độ hoạt động cho chân vừa chọn (Input/Output), có các mode như sau:
Hàm: void GPIO_Write(GPIO_TypeDef* GPIOx, uint8_t PortVal);
Chức năng: Xuất dữ liệu 08 bit ra các chân của Port x (Điều khiển 08 chân).
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
- PortVal: giá trị của từng chân trong Port.
Ví dụ: GPIO_Write(GPIOB, 0xFF); //Nối tất cả các chân của Port B lên mức cao (VCC - 3.3v).
Hàm: void GPIO_WriteHigh(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins);
Chức năng: Cấu hình một chân trong Port x lên mức cao (Điều khiển 01 chân).
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
- PortPins: Chân trong Port x cần điều khiển (GPIO_PIN_0 đến GPIO_PIN_7).
Ví dụ: GPIO_WriteHigh(GPIOB, GPIO_PIN_5); //Điều khiển chân số 5 của port B nối với Vcc(mức cao).
Hàm: void GPIO_WriteLow(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins);
Ví dụ: GPIO_WriteReverse(GPIOB, GPIO_PIN_5); // Nếu trạng thái trước đó của chân PB5 là 0 thì sẽ đổi thành 1 và ngược lại.
Giá trị trả về: Kiểu số nguyên 8bit không dấu uint8_t (0 -> 15)
Giá trị trả về: Kiểu số nguyên 8bit không dấu uint8_t (0 -> 15)
Giá trị trả về: Giá trị 1bit (0 hoặc 1).
#ifdef USE_FULL_ASSERT
Ở file code trên chúng ta phải thêm đoạn #ifdef USE_FULL_ASSERT ... #endif vào nếu không sẽ xuất hiện lỗi Error[Li005]: no definition for "assert_failed"... (IAR IDE)
chi tiết, các bạn có thể tham khảo bài viết này: https://codientu.org/threads/chuc-nang-cua-assert_failed.16190/
Nào, tiến hành nạp chương trình và tận hưởng thôi nào:
Bước 1: Chúng ta chọn biểu tượng make (F7).
Bước 2: Nhấn chọn biểu tượng Download and Debug (Ctrl + D).
Bước 3: Nhấn chọn Stop Debugging (Ctrl + Shift + D) để tiến hành run code.
Nếu khi click Download and Debug, chúng ta Debug từng dòng code thì code hoạt động đúng như khi chúng ta lập trình, nhưng khi nhấn stop debugging thì code không chạy - led không nhấp nháy như lúc debug (error while setting configuration with MCU name STM8S ... The Flash Memory Read-out protected option must be disabled for debug. Disabling this option will first erase the hole Flash Memory).
Nguyên nhân: khi mới mua board hoặc trước đó chúng ta đã chọn chế độ bảo vệ code. Để tắt chức năng bảo vệ code: chúng ta chọn tab ST-LINK >> Option bytes.. >> ROP => Read-out protection disabled.
Vậy là ở bài học này, chúng ta đã biết được cách tạo project, thêm thư viện, sử dụng thư viện và sử dụng chức năng GPIO (output) của STM8S. Hy vọng bài viết này sẽ giúp ích cho các bạn trong quá trình mới tiếp cận với STM8S.
Bài viết hôm nay, mình sẽ hướng dẫn các bạn sử dụng tính năng đầu tiên và cũng là quan trọng nhất của vi điều khiển, đó là giao tiếp Input/Output (hay còn được gọi là GPIO - General Purpose Input/Output). Như các bạn cũng đã biết, mỗi loại vi điều khiển đều có tính năng này. GPIO thực chất là những chân của Vi điều khiển có khả năng xuất (output) và nhận dữ liệu (input), tính năng này giúp cho chúng có thể điều khiển, giao tiếp với các ngoại vi và truyền/nhận được dữ liệu.
Trong bài viết này, mình sẽ hướng dẫn các bạn cách cấu hình sử dụng các chân của STM8S để phục vụ cho chức năng Input và Output. Như Ở bài trước chúng ta đã tạo được project để lập trình bằng trình biên dịch IAR. Hôm nay, chúng ta sẽ sử dụng project này để tiến hành lập trình. Để bắt đầu học một cách tốt nhất, các bạn cần xem qua sơ đồ nguyên lý, cách kết nối chân của Board mình đang sử dụng và sau đó xem qua Datasheet của em nó để có thể nắm rõ được chức năng của từng chân vi điều khiển. Trong bài viết này, mình sử dụng Board STM8S103F3P6.
Pinout STM8S103F3P6
|
![]() |
Board STM8S103F3P6 |
![]() |
Sơ đồ chân của Board STM8S103F3P6 |
ĐIỀU KHIỂN CÁC CHÂN STM8S VỚI CHỨC NĂNG OUTPUT
Trong ví dụ này, mình sẽ sử dụng Led có sẵn được kết nối với chân B5 trên Board STM8S103F3P6 để thực hành luôn nhé!
![]() |
Work Space đã tạo từ bài trước |
Đầu tiên, chúng ta tiến hành mở work space (Project) đã tạo từ bài trước (http://ratdongian.blogspot.com/2018/06/huong-dan-chi-tiet-tao-projects-lap.html) và sau đó tiến hành thêm thư viện stm8s_gpio.c để tiến hành lập trình (thư viện này tại đường dẫn: "..\Blink\STM8S_StdPeriph_Driver\src\stm8s_gpio.c"). Nếu chúng ta không thêm thư viện stm8s_gpio.c thì khi biên dịch chương trình sẽ xuất hiện lỗi: Error[Li005]: no definition for "GPIO_Init" và Error[Li005]: no definition for "GPIO_WriteReverse".
![]() |
Thêm thư viện stm8s_gpio.c |
![]() |
Thêm thư viện stm8s_gpio.c thành công |
![]() |
Định nghĩa Chip sử dụng cho thư viện stm8s.h |
Chúng ta quay lại file main.c để lập trình chương trình cho stm8s hoạt động. Đầu tiên trong file này, chúng ta cần thêm thư viện chuẩn stm8s.h bằng dòng lệnh: #include "stm8s.h"
Vì STM8S hoạt động tần số cao (16Mhz thạch anh nội - có thể cấu hình thạch anh ngoại) nên thời gian thực thi một lệnh của nó rất nhanh. Do đó, Để cho việc quan sát trạng thái Led(GPIO) được dễ dàng chúng ta cần một hàm Delay để làm trễ, đợi cho chúng ta có thể thấy được sự thay đổi của chúng. Thư viện chuẩn của STM8S (STM8S_StdPeriph_Driver) không hỗ trợ chúng ta chương trình Delay, nên chúng ta sẽ tạo một hàm delay bằng cách viết một đoạn chương trình:
void Delay(uint16_t nCount)
{
/* Decrement nCount value */
while (nCount != 0)
{
nCount--;
}
}
{
/* Decrement nCount value */
while (nCount != 0)
{
nCount--;
}
}
Lưu ý: Chương trình Delay trên làm trễ thời gian không chính xác, chỉ nên dùng để Test trạng thái khi mới tiếp cận với chức năng GPIO này (dễ dàng quan sát trạng thái). Nếu cần độ chính xác hơn, thì ở bài sau, mình sẽ hướng dẫn các bạn sử dụng Timer để tạo hàm Delay.
Dưới đây là một số hàm mà thư viện stm8s_gpio hỗ trợ chúng ta trong quá trình lập trình (tham khảo thêm trong file thư viện stm8s_gpio.h và stm8s_gpio.c):
Hàm: void GPIO_DeInit(GPIO_TypeDef* GPIOx);
Chức năng: Khởi tạo lại GPIOx về cấu hình mặc định.Tham số truyền vào: GPIOx với x là các port của STM8S (x tương ứng từ A -> I).
Ví dụ: Khởi tạo lại GPIO cho Port B => GPIO_DeInit(GPIOB);
Hàm: void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, GPIO_Mode_TypeDef GPIO_Mode);
Chứ cnăng: Khởi tạo GPIOx theo cấu hình (Input/Output)
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
- GPIO_Pin: Số thứ tự chân cần sử dụng trong Port lựa chọn (GPIO_PIN_0 đến GPIO_PIN_7, GPIO_PIN_LNIB, GPIO_PIN_HNIB, GPIO_PIN_ALL).
- GPIO_Mode: cài đặt chế độ hoạt động cho chân vừa chọn (Input/Output), có các mode như sau:
- GPIO_MODE_IN_FL_NO_IT: Ngõ vào thả trôi, Không sử dụng ngắt ngoài.
- GPIO_MODE_IN_PU_NO_IT: Ngõ vào có điện trở kéo lên, Không sử dụng ngắt ngoài.
- GPIO_MODE_IN_FL_IT: Ngõ vào thả trôi, Sử dụng ngắt ngoài.
- GPIO_MODE_IN_PU_IT: Ngõ vào có điện trở kéo lên, Sử dụng ngắt ngoài.
- GPIO_MODE_OUT_OD_LOW_FAST: Ngõ ra cực máng để hở, Logic thấp, Tần số cao 10Mhz.
- GPIO_MODE_OUT_PP_LOW_FAST: Ngõ ra dạng đẩy-kéo, Logic thấp, Tần số cao 10Mhz
- GPIO_MODE_OUT_OD_LOW_SLOW: Ngõ ra cực máng để hở, Logic thấp, Tần số thấp 2Mhz.
- GPIO_MODE_OUT_PP_LOW_SLOW: Ngõ ra dạng đẩy-kéo, Logic thấp, tần số thấp 2Mhz.
- GPIO_MODE_OUT_OD_HIZ_FAST: Ngõ ta cực máng để hở, Trở kháng cao, Tần số cao 10Mhz.
- GPIO_MODE_OUT_PP_HIGH_FAST: Ngõ ra dạng đẩy-kéo, Logic cao, tần số cao 10Mhz.
- GPIO_MODE_OUT_OD_HIZ_SLOW: Ngõ ta cực máng để hở, Trở kháng cao, Tần số thấp 2Mhz.
- GPIO_MODE_OUT_PP_HIGH_SLOW: Ngõ ra dạng đẩy-kéo, Logic cao, tần số thấp 2Mhz.
Hàm: void GPIO_Write(GPIO_TypeDef* GPIOx, uint8_t PortVal);
Chức năng: Xuất dữ liệu 08 bit ra các chân của Port x (Điều khiển 08 chân).
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
- PortVal: giá trị của từng chân trong Port.
Ví dụ: GPIO_Write(GPIOB, 0xFF); //Nối tất cả các chân của Port B lên mức cao (VCC - 3.3v).
Hàm: void GPIO_WriteHigh(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins);
Chức năng: Cấu hình một chân trong Port x lên mức cao (Điều khiển 01 chân).
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
- PortPins: Chân trong Port x cần điều khiển (GPIO_PIN_0 đến GPIO_PIN_7).
Ví dụ: GPIO_WriteHigh(GPIOB, GPIO_PIN_5); //Điều khiển chân số 5 của port B nối với Vcc(mức cao).
Hàm: void GPIO_WriteLow(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins);
Chức năng: Cấu hình một chân trong Port x xuống mức thấp (Điều khiển 01 chân).
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
- PortPins: Chân trong Port x cần điều khiển (GPIO_PIN_0 đến GPIO_PIN_7).
Ví dụ: GPIO_WriteLow(GPIOB, GPIO_PIN_5); //Điều khiển chân số 5 của port B nối với GND(mức thấp).
Hàm: void GPIO_WriteReverse(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins);
Chức năng: Đảo ngược trạng thái trước đó của một chân trong Port x.
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
- PortPins: Chân trong Port x cần điều khiển (GPIO_PIN_0 đến GPIO_PIN_7).
Hàm: uint8_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
Chức năng: Đọc giá trị ngõ vào hiện tại của 08 chân trong Portx.
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
Ví dụ: uint8_t data = GPIO_ReadInputData(GPIOB); // Đọc giá trị ngõ vào của 08 chân Port B.
Hàm: uint8_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
Chức năng: Đọc giá trị ngõ ra hiện tại của 08 chân trong Portx.
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
Ví dụ: uint8_t data = GPIO_ReadOutputData(GPIOB); // Đọc giá trị ngõ ra của 08 chân Port B.
Hàm: BitStatus GPIO_ReadInputPin(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin);
Chức năng: Đọc giá trị ngõ vào hiện tại của 01 chân trong Portx.
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
- GPIO_Pin: Chân trong Port x cần điều khiển (GPIO_PIN_0 đến GPIO_PIN_7).
Ví dụ: int1 data = GPIO_ReadInputPin(GPIOB, GPIO_PIN_0); // Đọc giá trị ngõ vào của chân PB5.
Hàm: void GPIO_ExternalPullUpConfig(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, FunctionalState NewState);
Chức năng: Cấu hình sử dụng điện trở kéo lên (Phía ngoài - lắp thêm điện trở kéo lên tại chân của Port x) cho 01 chân trong Port x.
Tham số truyền vào:
- GPIOx: Chọn Port của stm8s chứa chân chúng ta cần sử dụng mục đích GPIO (x: từ A -> I).
- GPIO_Pin: Chân trong Port x cần điều khiển (GPIO_PIN_0 đến GPIO_PIN_7).
- NewState: Trạng thái sau khi sử dụng điện trở kéo lên.
Ví dụ: GPIO_ExternalPullUpConfig(GPIOB, GPIO_PIN_0,1); // Sử dụng điện trở kéo lên bên ngoài cho chân PB0 (kéo lên vcc).
NẠP VÀ CHẠY CHƯƠNG TRÌNH
NẠP VÀ CHẠY CHƯƠNG TRÌNH
Và đây là code hoàn chỉnh:
#include "stm8s.h"
void Delay(uint16_t nCount)
{
/* Decrement nCount value */
while (nCount != 0)
{
nCount--;
}
}
{
/* Decrement nCount value */
while (nCount != 0)
{
nCount--;
}
}
int main( void )
{
GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST);
while(1){
GPIO_WriteReverse(GPIOB, GPIO_PIN_5);
Delay(0xFFFF);
}
}
{
GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST);
while(1){
GPIO_WriteReverse(GPIOB, GPIO_PIN_5);
Delay(0xFFFF);
}
}
#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 can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
* @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 can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
while (1)
{
}
}
#endif
Ở file code trên chúng ta phải thêm đoạn #ifdef USE_FULL_ASSERT ... #endif vào nếu không sẽ xuất hiện lỗi Error[Li005]: no definition for "assert_failed"... (IAR IDE)
chi tiết, các bạn có thể tham khảo bài viết này: https://codientu.org/threads/chuc-nang-cua-assert_failed.16190/
Nào, tiến hành nạp chương trình và tận hưởng thôi nào:
Bước 1: Chúng ta chọn biểu tượng make (F7).
Bước 2: Nhấn chọn biểu tượng Download and Debug (Ctrl + D).
Bước 3: Nhấn chọn Stop Debugging (Ctrl + Shift + D) để tiến hành run code.
Nếu khi click Download and Debug, chúng ta Debug từng dòng code thì code hoạt động đúng như khi chúng ta lập trình, nhưng khi nhấn stop debugging thì code không chạy - led không nhấp nháy như lúc debug (error while setting configuration with MCU name STM8S ... The Flash Memory Read-out protected option must be disabled for debug. Disabling this option will first erase the hole Flash Memory).
Nguyên nhân: khi mới mua board hoặc trước đó chúng ta đã chọn chế độ bảo vệ code. Để tắt chức năng bảo vệ code: chúng ta chọn tab ST-LINK >> Option bytes.. >> ROP => Read-out protection disabled.
Vậy là ở bài học này, chúng ta đã biết được cách tạo project, thêm thư viện, sử dụng thư viện và sử dụng chức năng GPIO (output) của STM8S. Hy vọng bài viết này sẽ giúp ích cho các bạn trong quá trình mới tiếp cận với STM8S.
Chào anh! Anh cho em hỏi khi nạp code thì em bị lỗi "Errors while setting configuration with MCU name STM8S003F3: gdi-error [40701]: Option bytes read error: not complemented; please use a programmer" là như thế nào vậy ạ?
Trả lờiXóaLỗi này mình cũng từng gặp mà không nhớ cách fix. Bạn chọn ST_LINK >> Option Bytes xem thử thế nào nhé.
Xóahttps://community.st.com/s/question/0D50X00009Xkb10/stm8-option-byte-problems
bài viết rất chi tiết cảm ơn bạn
Trả lờiXóa