HƯỚNG DẪN STM CƠ BẢN - B2

LẬP TRÌNH GPIO VÀ EXTERNAL INTERRUPT VỚI STM32

Author: Pham Cong Huy

GENERAL PURPOSE INPUT/OUTPUT (GPIO)

CÁCH HOẠT ĐỘNG

Trên board STM32F103C8T6 có các Port là GPIOA 16 chân, GPIOB 16 chân, GPIOC 3 chân, GPIOD 2 chân. Mỗi chân có thể được lập trình riêng là một đầu vào kỹ thuật số (digital input) hoặc đầu ra kỹ thuật số (digital output), ngoài ra các chân này còn được dùng chung cho các giao tiếp với ngoại vi khác.

Có 4 mode input:

Picture1

  • Input floating: chế độ thả nổi 2 khóa VDD, VSS đều mở, dữ liệu đầu vào sẽ được đi thẳng vào trigger. Trigger này sử dụng để phát hiện sườn clock (chân nhận dữ liệu USART, SPI...).
  • Input pull-up: chân được kéo lên trở, nếu chân không nối với mức điện áp thấp GND thì điện áp đọc được chân sẽ là mức điện áp cao (3,3V) hay giá trị 1 .
  • Input pull-down: chế độ trở kéo xuống mức điện áp thấp khóa VDD mở, VSS đóng chân ở mode này luôn ở mức điện áp thấp nếu không nối chân với nguồn điện áp cao.
  • Input analog: sử dụng để đọc tín hiệu tương tự như cảm biết nhiệt độ, biến trở.

Cùng với đó là 4 mode ouput:

Picture2

  • General push-pull: chế độ chân đẩy điện áp từ vi điều khiển ra bên ngoài, chân vi điều khiển nối với tải tiêu thụ và nối với GND.
  • General open drain: chế độ chân điều khiển mở và nhận điện áp từ nguồn điện áp bên ngoài.
  • Alternate push-pull: mode chân vi điều khiển xuất xung dao động của vi điều khiển luân phiên va bên ngoài chân, mode này được sư dụng như nguồn clock giữ nhịp hoặc chân truyền sữ liệu tốc độ cao (SPI, UART ...)
  • Alternate open dain: chế độ chân điều khiển mở và nhận luân phiên tín hiệu từ điện áp bên ngoài.

CẤU HÌNH GPIO

Trước tiên ta cần mở STM32Cube IDE lên và tạo một project mới. Tại bước cấu hình, ta click chuột trái vào một chân pin bất kì.

Picture3

Như ta thấy chân PA10 có 4 dòng GPIO, với GPIO_Analog liên quan đến các giao tiếp ADC, DAC và GPIO_EXTI10 liên quan đến ngắt ngoài. Vì vậy ta quan tấm đến 2 chế độ input và output. Ta hãy thử cấu hình chân PC13 ở chế độ output và một chân khác ở chế độ input.

Picture4

Trong mục GPIO ta cấu hình cho các chân đã chọn. Đối với các chân output ta có thể chọn mức điện áp xuất ra (High, Low), chọn chế độ output, tốc độ xuất, và đặt Label để thuận tiện cho việc lập trình. Với chế độ input, phần mềm cho ta lựa chọn mode pull - up hoặc pull-down hoặc là No pull-up/pull-down (chế độ floating).
Như trong hình ta đã cấu hình chân PA10 làm input với Label là CONTROL và PC13 làm output với Label là LED.

HAL GPIO FUNCTIONS

Trong series này chúng ta sẽ sử dụng thư việc HAL cho việc lập trình, dưới đây là một số hàm phục vụ cho việc lập trình GPIO:

  • HAL_GPIO_Init(GPIO_TypeDef * GPIOx, GPIO_InitTypeDef * GPIO_Init)

Đây là hàm khởi tạo cho chân GPIO, vì chúng ta đã cấu hình sẵn cho các chân sau đó generate nên hàm này sẽ được tạo tự động trong file main.c

Picture5

  • HAL_GPIO_ReadPin(GPIOx, GPIO_Pin)

         Đây là hàm đọc giá trị tại một pin. Trong đó GPIOx là Port và GPIO_Pin là Pin của chân chúng ta sẽ đọc giá trị. Nếu chúng ta chưa đặt Label cho chân thì cần gọi đúng theo Port và số hiệu chân của chân pin cần đọc. Ngược lại, nếu đã đặt tên ta có thể gọi theo tên đã define (các bạn có thể kiểm tra ở file main.h) ví dụ như ở việc cấu hình ở phần trên ta đọc giá trị chân PA10 theo hai cách:

                 + HAL_GPIO_ReadPin(GPIOA, GPIO_Pin_10)

                 + HAL_GPIO_ReadPin(CONTROL_GPIO_Port, CONTROL_Pin)

  • HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState)

        Đây là hàm ghi giá trị vào một pin. PinState có thể là GPIO_Pin_SET hoặc GPIO_Pin_RESET hoặc là giá trị của một biến.

  • HAL_GPIO_TogglePin(GPIOx, GPIO_Pin)

         Đây là hàm có chức năng đảo ngược giá trị của chân pin được gọi.

  • HAL_GPIO_LockPin(GPIOx, GPIO_Pin)

         Hàm khóa chức năng GPIO.

VÍ DỤ MINH HỌA

Ta cùng thử bật tắt Led PC13 với tín hiệu đọc từ nút nhấn nối với PA10.

Trước tiên ta cần cấu hình, ở mục GPIO ta cấu hình tương tự như phần ở trên, đối với chân input ta chọn mode Pull-up.

Picture6

Với mục SYS ta chọn Serial Wire tại Debug để nạp chương trình.

Picture7

Các phần còn lại có thể để mặc định. Sau đó ta Generate code.

Tại bước lập trình, đầu tiên ta cần khai báo một biến lưu giá trị nút nhấn.

Picture8

Trong hàm while (1) ta cho đọc giá trị nút nhấn và ghi nó vào LED_Pin.

Picture9

Tiếp theo nạp Build và nạp code xuống chip. Lưu ý vì chúng ta đã cấu hình chân PA10 là pull-up nên khi kết nối nút nhấn với board thì một đầu nút nhấn sẽ được nối với PA10 và đầu còn lại sẽ được nối với chân GND của board.

EXTERNAL INTERRUPT (EXTI)

CÁCH HOẠT ĐỘNG

Ngắt là một hành động tạm ngưng chương trình đang thực thi để phục vụ cho một chương trình ngắt khác khi gặp một sự kiện ngắt như thay đổi điện áp ở một chân pin, nhận được một kí tự trong UART hoặc ngắt với cờ báo tràn của bộ timer.Với STM32, việc quản lý ngắt được điều khiển bằng bộ NVIC (Nested vectored interrupt controller) tạm dịch là bộ điều khiển ngắt lồng nhau. Trong bài viết này, chúng ta sẽ tìm hiều về ngắt ngoài.

Có hai loại ngắt ngoài chính là ngắt ngoài trên các chân vi điều khiển và ngắt ngoài trên các ứng dụng như  RTC, USB, Ethernet…

STM32F103 chia làm 16-line ngắt ngoài riêng biệt từ EXTI0 đến EXTI15. Lưu ý với mỗi Line ngắt ta chỉ được chọn một chân ngắt ngoài vì Line đó đã dùng chung cho các chân ở port khác. Ví dụ ở EXTI0 chúng ta chỉ chần khai báo PA0 làm chân ngắt thì không được khai báo các chân PB0, PC0… nữa.

Picture10

Các Line ngắt này được phân vào các vector ngắt tương ứng. Các Line0, Line1, Line2, Line3, Line4 sẽ được phân vào các vector ngắt riêng biệt EXTI0, EXTI1, EXTI2, EXTI3, EXTI4, còn từ Line5 đến Line9 sẽ được phân vào vector ngắt EXTI9_5, Line10 đến Line15 được phân vào vecotr EXTI15_10. Để tìm hiểu kỹ hơn về các vector ngắt cũng như các thanh ghi phụ vụ ngắt các bạn có thể đọc qua Reference Manual của chip.

CẤU HÌNH

Chúng ta tạo một project mới và cấu hình cho hai chân PA0 và PA10 ở mode EXTI

Picture11

Sang với phần System Core, mục GPIO chúng ta chọn vào một chân EXTI.

Trong phần GPIO mode chúng ta chú ý đến 3 chế độ:

  • External Interrupt Mode Rising edge: ngắt khi phát hiện xung lên.
  • External Interrupt Mode Falling edge: Ngắt khi phát hiện xung xuống.
  • External Interrupt Mode Rising/Falling: Ngắt khi có xung lên hoặc xuống.

Trong phần GPIO Pull-up/Pull-down chúng ta có thể chọn giá trị mặc định của chân.

Picture12

Sang mục NVIC hãy tích vào ô Enable cho hai vector ngắt EXTI line0 và EXTI line[15..10].

Picture12

HAL EXTI FUNCTIONS

  • HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_x)

         Đây là hàm xử lí yêu cầu khi có một tín hiệu ngắt. Khi đã cấu hình và Generate code xong các bạn hãy vào file stm32f1xx_it.c và tìm EXTIx_IQRHandle(void) chúng ta sẽ thấy hàm này, và có thể code chương trình ngắt ngay dưới.

Picture14

Vì bên trong hàm này đã được lập trình sẵn cho ta các công việc:

             + __HAL_GPIO_EXTI_GET_IT(GPIO_Pin) : đọc giá trị cờ ngắt.

             + __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin): xóa cờ ngắt.

              + HAL_GPIO_Callback(GPIO_Pin): gọi đến hàm xử lý của người lập trình. Ứng với mỗi chân ngắt khi có tín hiệu ngắt, giá trị GPIO_Pin sẽ được trả về đúng chân ngắt đó.

Picture15

  • Ngoài ra còn một số hàm khác có chức năng cấu hình cho các chân EXTI, các hàm này đã được tạo sẵn khi ta cấu hình EXTI cho các chân nên các bạn có thể tham khảo ở tài liệu Decription.

VÍ DỤ MINH HỌA

Chúng ta sẽ sử dụng các EXTI ở các Line0, Line6, Line10 để lần lượt cho đèn sáng, tắt và nhấp nháy.

Chúng ta sẽ cấu hình cho các chân ngắt. Ở mục GPIO ta sẽ chọn mode Falling edge và Pull-up.

Picture16

Tiếp theo các bạn vào mục NVIC và tích chọn cho Enable cho các chân ngắt, trong mục SYS/Debug chọn Serial Wire và sau đó Genarate code.

Trong hàm main.c ta khai báo một biến Flag = 0 biến Flag này sẽ điều khiển các hành động của LED trong hàm while(1) và được thay đổi giá trị trong các hàm ngắt. Chúng ta sẽ đi định nghĩa lại hàm Callback của chương trình, vì hàm này được dùng chung có tất cả tín hiệu ngắt ngoài trên các chân nên ta cần phân ra các trường hợp để phân biệt các chân.

Picture17

Còn một cách khác nếu như các bạn không muốn tự định nghĩa lại hàm Callback là tìm file stm32f1xx_it.c rồi tìm đến từng hàm IQR_Handle của các line EXTI và viết đoạn mã ngắt.

Picture18

Lưu ý: để sử dụng biến Flag đã khai báo ở file main.c thì chúng ta cũng cần khai báo ở file stm32f1xx_it.c một lần nữa.

Picture19

Trong hàm while(1) ta sẽ cho LED được tùy chỉnh theo các chế độ ứng với giá trị mà biến Flag đang giữ sau các tín hiệu ngắt.

Picture20

Sau cùng các bạn hãy nạp code lên chip và thử trải nghiệm nhé.