# (志航) [STM32]序列埠通訊、外部中斷、窗口看門狗(WWDG)
## 實驗九-序列埠通訊 | 實驗十-外部中斷 | 實驗十二-窗口看門狗(WWDG)
### 序列埠通訊
:::success
USART(Universal Synchronous Asynchronous Receiver Transmitter,通用同步/異步收發器) 是嵌入式系統中兩種常見的通訊方式。
我們這邊使用的是Asynchronous(非同步模式):發送端和接收端需要事先協商好一個固定的波特率來同步通信。
:::
***
#### 硬體設置



PIN腳的TX,RX與GND分別接到USB轉TTL的RXD、TXD、GND
___
#### 主要程式碼
``` c=
#include "string.h"
uint8_t Rxbuf[3];
uint16_t L[4]= {LD4_Pin, LD3_Pin, LD5_Pin, LD6_Pin};
int main(void)
{
//啟動 UART DMA 接收
HAL_UART_Receive_DMA(&huart1, Rxbuf, sizeof(Rxbuf));
while (1)
{
if (strcmp((char *)Rxbuf, "FWD") == 0) // 接收到 'FWD',開啟正轉
{
for (int i = 0; i < 4; i++) {
HAL_GPIO_WritePin(GPIOD, L[i] , GPIO_PIN_SET);
for (int j = 0; j < 4; j++) {
if (i != j ) {
HAL_GPIO_WritePin(GPIOD, L[j], GPIO_PIN_RESET);
}
}
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOD, L[i] , GPIO_PIN_RESET);
HAL_Delay(300 );
}
}
else if (strcmp((char *)Rxbuf, "REV") == 0) // // 接收到 'REV',開啟逆轉
{
for (int i = 3; i >= 0; i--) {
HAL_GPIO_WritePin(GPIOD, L[i] , GPIO_PIN_SET);
for (int j = 0; j < 4; j++) {
if (i != j ) {
HAL_GPIO_WritePin(GPIOD, L[j], GPIO_PIN_RESET);
}
}
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOD, L[i] , GPIO_PIN_RESET);
HAL_Delay(300 );
}
}
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
if (UartHandle->Instance == USART1)
{
// 顯示接收到的字元
printf("Input: %s\r\n", Rxbuf);
// 重新啟動 UART 接收,以便繼續接收下一筆資料
HAL_UART_Receive_DMA(&huart1, Rxbuf, sizeof(Rxbuf));
}
}
```
#### 成果
{%youtube p0gpIsDbMKI%}
---
### 外部中斷
:::success
外部中斷(External Interrupt):通過外部硬件引腳觸發中斷。當指定的GPIO引腳發生邊沿變化,就會觸發中斷,MCU會暫停當前的任務,進入中斷服務程序
:::
___
#### 硬體設置



___
#### 主要程式碼
打開stm32f4xx_it.c
:::success
==HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)== 此回調函數可從下列路徑查詢使用

:::
``` c=
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == PB3_Pin) // 確認是PB3引腳觸發的中斷
{
if (HAL_GPIO_ReadPin(GPIOB, PB3_Pin) == GPIO_PIN_SET) // 如果PB3為高電平
{
for (int i = 0; i < 4; i++)
{
HAL_GPIO_WritePin(GPIOB, LD10_Pin, GPIO_PIN_SET);
HAL_Delay(200);
HAL_GPIO_WritePin(GPIOB, LD10_Pin, GPIO_PIN_RESET);
HAL_Delay(200);
}
}
}
}
```
main.c
``` c=
int main(void)
{
uint16_t L[4]= {LD4_Pin, LD3_Pin, LD5_Pin, LD6_Pin};
while(1) {
/* USER CODE END WHILE */
MX_USB_HOST_Process();
/* USER CODE BEGIN 3 */
for (int i = 0; i < 4; i++) {
if(HAL_GPIO_ReadPin(GPIOD, SW1_Pin) == 1){
HAL_GPIO_WritePin(GPIOD, L[i], GPIO_PIN_SET);
}
for (int j = 0; j < 4; j++) {
if (i != j && HAL_GPIO_ReadPin(GPIOD, SW1_Pin) == 1) {
HAL_GPIO_WritePin(GPIOD, L[j], GPIO_PIN_RESET);
}
}
HAL_Delay(200);
HAL_GPIO_WritePin(GPIOD, L[i], GPIO_PIN_RESET);
HAL_Delay(200);
}
}
}
```
___
#### 成果
{%youtube DyOgAX2GwpQ%}
---
### 窗口看門狗(WWDG)
:::success
窗口看門狗定時器(WWDG)監控系統運行,必須在特定時間窗口內重置,否則將觸發復位。它提高系統穩定性,防止死循環或故障,廣泛應用於嵌入式系統和工業控制等領域。
:::
___
#### 硬體設置




:::success
127(0x7F):當 WWDG 開始工作時,計數器值通常被設置為 0x7F(127),這代表計數器的起始值。
63(0x3F):當計數器倒數到 0x3F(63)時,如果程序沒有在窗口期內(即計數器值介於窗口值和 0x3F 之間)重置計數器,系統將觸發重啟。
:::
只有在Refresh allowed區間Refresh WWDG才不會系統重啟。 時間計算
#### 主要程式碼
``` c=
int main(void)
{
HAL_GPIO_TogglePin(GPIOD, LD3_Pin);
while (1)
{
/* USER CODE END WHILE */
MX_USB_HOST_Process();
/* USER CODE BEGIN 3 */
//(1/36000000)*4096*2^3*(127-80) ~ 44 ms Disable reloadin
//(1/36000000)*4096*2^3*(80-63+1 ) ~ 16 ms
//(1/36000000)*4096*2^3*(127-63+1) ~ 59 ms 44~59 ms Refresh WWDG
//HAL_Delay(40); // Disable reloading
HAL_Delay(50); // Normal, safe
//HAL_Delay(65); // timeout, system reset
HAL_WWDG_Refresh(&hwwdg);
HAL_GPIO_TogglePin(LD4_GPIO_Port, LD4_Pin);
}
}
```
EarlyWakeupCallback : WWDG早期喚醒中斷回調函數
```c=
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg) {
HAL_GPIO_TogglePin(LD6_GPIO_Port, LD6_Pin);
}
```
___
#### 成果
{%youtube vgjF_HG_FRA%}
{%youtube b0LyNaG5tO8%}
___
## **實驗進度**
- [x] 6-跑馬燈實驗
- [x] 7-蜂鳴器實驗
- [x] 8-按鈕輸入實驗
- [x] 9-序列埠通訊實驗
- [x] 10-外部中斷實驗
- [x] 12-窗口門狗(WWDG)實驗
- [ ] 13-定時器中斷實驗
- [ ] 14-PWN輸出實驗
- [ ] 16-電容觸摸按鍵實驗
- [ ] 18-TFTLCD顯示實驗
- [ ] 19-USMART調試組件實驗
- [ ] 20-RTC即時時鐘實驗
- [ ] 23-ADC實驗
- [ ] 29-IIC實驗
- [ ] 30-SPI實驗
- [ ] 36-DHT11數位溫濕度感測器實驗