2020年12月28日 星期一

STM32CubeMX PWM實現呼吸燈​​效果

在STM32CubeMX中新建項目,選擇正確的MCU型號

根據板子實際情況設置時鐘(STM32F100RBT的最高主頻是24M)

設置PC9 管腳為TIM3_CH4, 即定時器TIM3的Channel4

然後設置TIM3的Channel4為PWM Generation CH2

我們知道TIM3是掛在APB1總線上的,看時鍾樹我們知道APB1總線的Timer頻率是24MHz。

配置TIM3參數,預分頻係數設置為24-1, 自動重載值設置為1000-1,那麼PWM頻率為24,000,000/24/1000=1000Hz,即1KHz。由於LED是低電平點亮,所以我們把極性設置為low。

在main.c中,先定義一個變量存儲我們設置的佔空比

  1. /* USER CODE BEGIN 1 */
  2. uint16_t dutyCycle = 0;
  3. /* USER CODE END 1 */

然後使能TIM3的PWM Channel2 輸出。

  1. /* USER CODE BEGIN 2 */
  2. HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_4);
  3. /* USER CODE END 2 */

然後在while(1)中改變dutyCycle的值

  1. /* USER CODE BEGIN WHILE */
  2. while (1)
  3. {
  4. while (dutyCycle < 1000)
  5. {
  6. dutyCycle ++;
  7. __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, dutyCycle);
  8. // TIM3->CCR2 = dutyCycle;
  9. HAL_Delay(1);
  10. }
  11. while (dutyCycle)
  12. {
  13. dutyCycle --;
  14. __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, dutyCycle);
  15. // TIM3->CCR2 = dutyCycle;
  16. HAL_Delay(1);
  17. }
  18. HAL_Delay(200);
  19. /* USER CODE END WHILE */

 

2020年12月25日 星期五

STM32CubeMX 串行通信(USART)

本章以串口為例講解,HAL 庫輪詢,中斷,DMA 三種編程模型。
1.前情回顧
       在串行通信中,一個字符一個字符地傳輸,每個字符一位一位地傳輸,並且傳輸一個字符時,總是以“起始位”開始,以“停止位”結束。在進行傳輸之前,雙方一定要使用同一個波特率設置。波特率就是每秒鐘傳輸的數據位數。
       常用的兩種基本串行通信方式包括同步通信和異步通信。我們通常使用的是異步通信.異步通信規定傳輸的數據格式由起始位(start bit)、數據位(data bit)、奇偶校驗位(parity bit)和停止位(stop bit)組成。


2.重定義printf函數。
        打開STM32CubeMX新建工程,選擇STMF746IGT6芯片,選擇外部高速晶振(HSE)。USART1選擇為異步通信方式。PA10設置RX接收,PA9設置為TX發送。

配置時鐘系統時鐘為216MHz,STMF746可以單獨配置USART時鐘,默認為108Mhz。


串口配置設置波特率為115200 Bits/s。傳輸數據長度為8 Bit。奇偶檢驗無,停止位1.其他參數默認。


        生成報告以及代碼,編譯程序。在usart.c文件中可看到串口1的初始化函數MX_USART1_UART_Init(void),以及管腳配置函數HAL_UART_MspInit() 

        C語言中的標準庫中所用的標準輸出函數,默認的輸出設備是顯示器,要實現串口或LCD的輸出,必須重新定義標準庫函數里與輸出函數相關的函數。例如:printf輸出到串口,需要將fputc裡面的輸出指向串口(重定向),方法如下:只要自己添加一個int fputc(int ch, FILE *f)函數,能夠輸出字符就可以了。

        在usart.c文件後面添加如下代碼,代碼中添加了#ifdef宏定義進行條件編譯,如果使用GUNC編譯,則PUTCHAR_PROTOTYPE定義為int __io_putchar(int ch)函数,否则定义为int fputc(int ch, FILE *f)函数。

01/* USER CODE BEGIN 1 */
02#ifdef __GNUC__
03  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
04     set to 'Yes') calls __io_putchar() */
05  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
06#else
07  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
08#endif /* __GNUC__ */
09/**
10  * @brief  Retargets the C library printf function to the USART.
11  * @param  None
12  * @retval None
13  */
14PUTCHAR_PROTOTYPE
15{
16  /* Place your implementation of fputc here */
17  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
18  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
19  
20  return ch;
21}
22/* USER CODE END 1 */

其中HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);這個語句表示通過串口1發個一個字符。ch為字符的存儲地址,0xFFFF為超時時間。在stm32f7xx_hal_uart.c文件中可以找到HAL_UART_Transmit函數。


在main.c文件中添加應用函數。

01/* USER CODE BEGIN 2 */
02  printf("\n\r UART Printf Example: retarget the C library printf function to the UART\n\r");
03/* USER CODE END 2 */
04 
05/* Infinite loop */
06/* USER CODE BEGIN WHILE */
07while (1)
08{
09/* USER CODE END WHILE */
10 
11/* USER CODE BEGIN 3 */
12      printf("\n\r welcome to www.waveshere.com !!!\n\r");
13      HAL_Delay(1000);
14}
15/* USER CODE END 3 */

編譯程序並下載到開發板。用USB線連接開發板到電腦,在電腦上打開串口調試助手。選擇對應的串口號,設置波特率為115200。按下復位按鍵會接收到如圖信息。


打開stm32f7xx_hal_uart.h頭文件,在文件後最後面可以看到有如下操作串口的函數。


串口的發送接收函數:
HAL_UART_Transmit();串口輪詢模式發送,使用超時管理機制。
HAL_UART_Receive();串口輪詢模式發送,使用超時管理機制。
HAL_UART_Transmit_IT();串口中斷模式發送,
HAL_UART_Receive_IT();串口中斷模式發送
HAL_UART_Transmit_DMA();串口DMA模式發送
HAL_UART_Receive_DMA();串口DMA模式發送

串口相關的中斷函數:
HAL_UART_TxHalfCpltCallback():一半數據(half transfer)發送完成後,通過中斷處理函數調用。
HAL_UART_TxCpltCallback():發送完成後,通過中斷處理函數調用。
HAL_UART_RxHalfCpltCallback():一半數據(half transfer)接收完成後,通過中斷處理函數調用。
HAL_UART_RxCpltCallback():接收完成後,通過中斷處理函數調用。
HAL_UART_ErrorCallback():傳輸過程中出現錯誤時,通過中斷處理函數調用。

可看到串口發送和就是有三種通信模式:
       第一種是上面用到的輪詢的模式。CPU不斷查詢IO設備,如設備有請求則加以處理。例如CPU不斷查詢串口是否傳輸完成,如傳輸超過則返回超時錯誤。輪詢方式會佔用CPU處理時間,效率較低。
       第二種就是中斷控制方式。當I/O操作完成時,輸入輸出設備控制器通過中斷請求線向處理器發出中斷信號,處理器收到中斷信號之後,轉到中斷處理程序,對數據傳送工作進行相應的處理。
       第三種就是直接內存存取技術( DMA)方式。所謂直接傳送,即在內存與IO設備間傳送一個數據塊的過程中,不需要CPU的任何中間干涉,只需要CPU在過程開始時向設備發出“傳送塊數據”的命令,然後通過中斷來得知過程是否結束和下次操作是否準備就緒。

3.中斷模式。
        打開STM32CubeMX重新建工程,配置和前面一樣。只是這個工程中,開啟了串口中斷。



生成報告以及代碼,編譯程序。在main函數前面添加兩個數組變量。

1/* Private variables ---------------------------------------------------------*/
2  
3/* USER CODE BEGIN PV */
4/* Private variables ---------------------------------------------------------*/
5uint8_t aTxStartMessage[] = "\r\n****UART-Hyperterminal communication based on IT ****\r\nEnter 10 characters using keyboard :\r\n";
6  
7/* Buffer used for reception */
8uint8_t aRxBuffer[20];
9/* USER CODE END PV */

在main函数中添加两个语句通过串口中断发送aTxStartMessage数组的数据和接收数据10个字符,保存在数组aRxBuffer中

1/* USER CODE BEGIN 2 */
2    HAL_UART_Transmit_IT(&huart1, (uint8_t *)aTxStartMessage, sizeof(aTxStartMessage));
3    HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 10);
4/* USER CODE END 2 */

在main.c文件后面添加中断接收完成回调函数。中断回调函数中将接收到的数据又通过串口发送回去。

01/* USER CODE BEGIN 4 */
02/**
03  * @brief Rx Transfer completed callbacks
04  * @param huart: uart handle
05  * @retval None
06  */
07void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
08{
09  /* Prevent unused argument(s) compilation warning */
10  UNUSED(huart);
11   
12  /* NOTE : This function should not be modified, when the callback is needed,
13            the HAL_UART_RxCpltCallback can be implemented in the user file
14   */
15    HAL_UART_Transmit(&huart1, (uint8_t *)aRxBuffer, 10,0xFFFF);
16}
17/* USER CODE END 4 */

编译程序并下载到开发板。用USB线连接开发板到电脑,在电脑上打开串口调试助手。选择对应的串口号,设置波特率为115200。按下复位按键会接收到aTxStartMessage数组的数据。通过串口助手发送10个字符,串口助手回显示发送的数据。注意:串口要发够10个字符串,才会触发中断。少于10个字符则不会触发中断,串口不会显示发送的数据。超过10个字符,串口只会发送10个字符回来显示。 

資料來源:https://www.waveshare.net/study/article-644-1.html