GPIO: Chớp tắt led PC13 [LẬP TRÌNH STM32F103C8T6]

GPIO là gì?

GPIO (General-purpose Input/Output) là một chức năng ngoại vi phổ biến trong vi điều khiển, cung cấp các chân đầu vào và đầu ra có thể được điều khiển bởi người dùng. Nó tồn tại trong hầu hết các loại vi điều khiển, bao gồm cả những vi điều khiển 8-bit như AVR hoặc PIC. Tuy nhiên, khác với các vi điều khiển 8-bit mà chỉ có 8 chân IO trên mỗi port, các vi điều khiển 32-bit thường có đến 16 chân IO trên mỗi port. Ví dụ, chip STM32F103C8Tx có 3 port GPIO chính là GPIOA, GPIOB, GPIOC. Trong số đó, GPIOA và GPIOB trên kit thường có đủ 16 chân GPIO, nhưng không phải tất cả các port đều có số lượng chân tương tự.

STM32 GPIO hoạt động như thế nào?

Tiếp theo chúng ta đến phần cấu trúc 1 chân GPIO của chip:

Có 2 khối điều khiển khác nhau (khung hình nét đứt) như ở hình trên:

  • Input Driver: Bao gồm thanh ghi Input Data (IDR), và 1 trigger. Tín hiệu Input ngoài việc được ghi vào IDR còn theo các đường Analog để vào bộ ADC, hoặc theo đường Alternate function input vào các ngoại vi khác
  • Output Drive: Bao gồm thanh ghi Output Data (ODR), một khối output control để chọn tín hiệu ra là từ ODR hay từ các ngoại vi khác. Tiếp đến điều khiển 2 mosfet cho điện áp ra ở I/O pin

Chức năng của STM32 GPIO bao gồm:

Input:

  • Input pull up: Đầu vào có trở kéo lên (điện áp mặc định trên chân là Vcc)
  • Input pull down: Đầu vào có trở kéo xuống (điện áp mặc định trên chân là 0V)
  • Input floating: Đầu vào thả nổi, điện áp không cố định dao động từ 0V tới Vcc
  • Analog: Đầu vào tương tự, dùng để đo ADC

Output:

  • Ouput Push Pull: Đầu ra dạng đẩy kéo, tín hiệu sẽ chỉ có Vcc hoặc 0V tương ứng với Bit 1 và 0 ghi vào chân đó
  • Ouput Opendrain: Đầu ra dạng cực máng hở. Chỉ có thể kéo về 0V bằng cách ghi bit 0, khi ghi bit 1, chân IO sẽ có điện áp tương ứng với nguồn nối vào IO đó
  • Alternate function Push Pull: Đầu ra kểu đẩy kéo sử dụng trong các ngoại vi
  • Alternate function Open Drain: Đầu ra dạng cực máng hở, sử dụng trong các ngoại vi (thường gặp trong I2C)

Mặc định khi người dùng không cấu hình, trạng thái của các chân I/O pins là input floating. Bài viết này sẽ hướng dẫn về chức năng của khối Output. Sau đây sẽ là sơ lược về cấu trúc phần cứng và khối điều khiển Output.

Các thanh ghi dữ liệu:

Bit set/reset register:

 Ở mỗi chân general-purpose I/O port đều có 2 thanh ghi cấu hình 32 bit (GPIOx_CRL – Control Register Low, GPIO_CRH – Control Register High):

–  Thanh ghi 32 bit dùng để set/reset các bit ở các chân IO (GPIOx_BSRR: Bit Set Reset Register)

–  Thanh ghi 16 bit reset các bit ở các chân IO (GPIOx_BRR: Bit Reset Register) với x là các port của vi điều khiển.

Output data register:

Dữ liệu sau khi các bit đã được set/reset ở thanh ghi trên sẽ được truyền sang thanh ghi dữ liệu đầu ra 32bit (GPIOx_ODR: Output data register) và truyền đến khối điều khiển để xuất mức tín hiệu cho chân IO. Ngoài ra đối với thanh ghi này, chúng ta có thể đọc dữ liệu để xem trạng thái hiện tại của các chân IO đang ở mức “1” hoặc mức “0”.

Cách xuất mức tín hiệu output thông qua khối CMOS:

Khi một I/O Pin được cấu hình hoạt động với chức năng OUTPUT thì:
Khối điều khiển OUPUT được sử dụng với các chế độ: Open drain mode hoặc Push-pull mode.
– Với chế độ Open drain: Một giá trị bit bằng 0″ ở thanh ghi ODR sẽ làm N-MOS dẫn, P-MOS ngưng dẫn, lúc này chân vi điều khiển có mức logic 0 (được nối với GND); Một giá trị bit bằng “1” ở thanh ghi ORD sẽ làm ngưng dẫn cả N-MOS và P-MOS, chân tương ứng sẽ ở trạng thái Hi-Z (trở kháng cao). 
– Với chế độ Push-pull:  Một giá trị bit bằng 0 ở thanh ghi ODR sẽ làm N-MOS dẫn và P-MOS ngưng dẫn, lúc này chân vi điều khiển có mức logic 0 (được nối với GND); Một giá trị bit bằng “1” ở thanh ghi ODR sẽ làm N-MOS ngưng dẫn và P-MOS dẫn. Lúc này chân vi điều khiển có mức logic 1 (được nối với VDD).
Như vậy, để  điều khiển giá trị logic của một pin được cấu hình hoạt động với chức năng OUPUT thì chúng ta cần ghi giá trị logic vào thanh ghi Ouput Data (GPIOx_ODR). Bit tương ứng của thanh ghi sẽ điều khiển pin ở vị trí tương ứng. Ví dụ: BIT thứ 0 của thanh ghi GPIOA_ODR sẽ điều khiển pin tương ứng là PA0.

Chúng ta sẽ sử dụng CubeMX để sinh code và lập trình trên môi trường KeilC-V5.  Khi sinh code,  chúng ta sẽ làm việc dựa trên lớp thư viện HAL-Hardware Abstraction Layer. Thư viện này được xây dựng dựa trên các thư viện tiêu chuẩn (Std) của STM32, để tiếp cận được nhanh chóng dòng vi điều khiển này thì chúng ta sẽ không đi quá sâu vào việc set/reset các bit ở trong thanh ghi. Mà sử dụng phần mềm CubeMX để sinh code và sử dụng các hàm GPIO có sẵn trong thư viện HAL.

Tiếp theo chúng ta sẽ đi sơ lược các chân GPIO của kit STM32F103C8T6:

Ở trên kit này bao gồm có 3 Port chính:

  • Port A: 16 chân
  • Port B: 16 chân
  • Port C: 3 chân

Ở Port C chân thứ 13, trên kit đã layout sẵn một đèn led, chúng ta sẽ sử dụng đèn led này để thực hành với chức năng output push-pull

Tạo dự án mới bằng STM32CubeMX

Bước 1

Mở STM32CubeMX và tạo một project mới cho bo mạch STM32 của bạn.

Click New Project or Menu -> File -> New Project. Hoặc click vào Access to MCU selector , các bạn cũng có thể chọn Access to Board Selector nếu sử dụng các KIT của hãng.

Bước 2

STM32F103C8 vào ô tìm kiếm, chọn chip và nhấn Start project

Bước 3

Cài đặt Serial wire để nạp code theo chuẩn SWDIO-SWCLK

Trong mục SYS/Debug  các bạn chọn Serial Wire, để chọn 2 chân PA13 và PA14 là chân nạp, nếu ko chọn mỗi khi cần nạp bạn phải giữ nút reset và nạp mới được.

Còn lại để mặc định

Bước 4

Trong RCC chọn HSE nếu chạy bằng thạch anh ngoài, ko chọn gì sẽ chạy bằng thạch anh nội

Bước 5

Click chuột phải vào chân PC13 sau đó tích vào ô GPIO_Output

Cấu hình các chân GPIO như ở dưới:

  • GPIO output level: “LOW” (Trạng thái ban đầu của led và sẽ được kích khi xuất mức “0” tại chân IO)
  • GPIO mode: “Output push-pull”
  • Maximum output speed: Đối với các dòng vi điều khiển có tốc độ xử lý nhanh từ vài chục MHz trở lên, thì chúng ta phải khai báo tốc độ dao động tại chân đó để đáp ứng với tốc độ xử lý của vi điều khiển. Hiện tại, chúng ta đang sử dụng nguồn dao động nội với tốc độ là 8MHz nên ở đây sẽ chọn “LOW”
  • User Label: “LED”

Bước 6

Phần Clock config, để mặc định đó là thạch anh nội 8Mhz, phần Project Manager Gõ tên project, nơi lưu trữ, chọn tool chain là MDK-ARM V5, sau đó nhấn Generate Code

Hướng dẫn lập trình nhấp nháy led PC13 sau khi đã sinh code:

 Sau khi sinh code STM32CubeMX sẽ hiển thị thông báo

  • Chọn open project
  • Chọn function:

Ở đây sẽ có các hàm liên quan đến điều khiển các chân GPIO:

HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)để đảo trạng thái của led PC13. Ở đây mình sẽ truyền vào 2 tham số, thứ nhất là Port cần sử dụng và tham số thứ 2 là chân IO cần sử dụng cụ thể: HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13)

Ngoài ra có thể xuất mức “1” hoặc mức “0” tại chân IO thông qua hàm:

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);

  • Hàm while(1) mình sẽ đảo trạng thái của led 500ms 1 lần.
  • Hàm Toggle có nhiệm vụ đảo trạng thái của Pin LED, Hal_Delay(500) sẽ cho CPU chờ mỗi 500ms và lien tục lặp đi lặp lại trong while
  • Lưu ý: các bạn phải viết code trong khoảng USER CODE BEGIN và USER CODE END nhé. Vì nếu bạn thay đổi trong file Cube và Gen code lại, các code ngoài khoảng này đều bị xóa hết.
  while (1)
  {
    /* USER CODE END WHILE */
			HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
			HAL_Delay(500);
			//HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
			//HAL_Delay(500);
    /* USER CODE BEGIN 3 */
  }

Hoặc

 while (1)
  {
    /* USER CODE END WHILE */
			HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
			HAL_Delay(500);
			HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
			HAL_Delay(500);
		/*
			HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
			HAL_Delay(500);
			HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
			HAL_Delay(500);
		*/
    /* USER CODE BEGIN 3 */
  }
  • Build chương trình 
  • Nạp code vào bộ nhớ flash của vi điều khiển

Chúc bạn thành công!

Nhận xét

Mới hơn Cũ hơn