1. 程式人生 > >STM32F10x USART串列埠對映功能實現串列埠通訊 485初始化

STM32F10x USART串列埠對映功能實現串列埠通訊 485初始化

這篇文章很有用!新手不要自以為是,STM32串列埠管腳重對映小樣你會嗎???

STM32F10x 系列微控制器中都包含了USART 模組,所謂USART,就是通用同步非同步收發器。通用同步非同步收發器(USART)提供了一種靈活的方法與使用工業標準NRZ非同步序列資料格式的外部裝置之間進行全雙工資料交換。它支援同步單向通訊和半雙工單線通訊,也支援LIN(區域性互連網)智慧卡協議和IrDA(紅外資料組織)SIR ENDEC規範,以及調變解調器(CTS/RTS)操作。它還允許多處理器通訊。

從前面的介紹可知USART模組功能非常的強大。這裡我只簡單講講如何用USART模組來實現標準EIA-232 

串列埠通訊。

用過微控制器的人肯定都接觸過串列埠,設定串列埠無非就是設定波特率、資料位、停止位、奇偶校驗位。傳送接收也就三種基本方式,輪詢、中斷和DMASTM32F10x USART 模組也不過如此。所以我重點講講我在除錯程式碼時犯得各種錯誤,那些很容易得到的程式碼就不詳細的講解了。

首先說說我的硬體環境。還是那塊神舟4號開發板,用的是串列埠2,對應的是USART2。預設情況下USART2是連線到IOA的,但是我這裡需要將USART的管腿重定向到IOD上。具體的管腿的關係參見下表。這個表是從STM32參考手冊上拷下來的。

初始化USART的程式碼很簡單。USART2 連線到

APB1 總線上了,先要開啟USART2的時鐘,然後設定波特率一類的引數。

  1. USART_InitTypeDef USART_InitStructure;  
  2. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);  
  3. USART_InitStructure.USART_BaudRate = 9600;  
  4. USART_InitStructure.USART_WordLength = USART_WordLength_8b;  
  5. USART_InitStructure.USART_StopBits = USART_StopBits_1;  
  6. USART_InitStructure.USART_Parity = USART_Parity_No;  
  7. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  8. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  
  9. USART_Init(USART2, &USART_InitStructure );   

這樣設定了還不能使用。因為我們將USART2 重定向了。重定向操作需要寫複用重對映和除錯I/O配置暫存器(AFIO_MAPR)GPIO_PinRemapConfig() 可以完成這項任務。

  1. GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);  

光這樣操作還不夠。STM32參考手冊上有這麼一段話:

對暫存器AFIO_EVCRAFIO_MAPRAFIO_EXTICRX進行讀寫操作前,應當首先開啟AFIO的時鐘。參考第6.3.7APB2外設時鐘使能暫存器(RCC_APB2ENR)

所以需要先開啟AFIO的時鐘。因此,USART2的重定向需要兩步操作:

  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);  
  2. GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);  

我原以為這樣就能工作了,可是結果還是什麼都沒有輸出。沒辦法只能繼續研究。在讀GPIO的相關章節時看到下圖讓我恍然大悟。

USART2的輸入輸出都是借用PD口管腿,PD 口的時鐘卻還沒給。用到的幾個IO 埠也沒有設定相應的輸入輸出狀態。在讀到8.1.9 複用功能配置這一小節時發現瞭如下的表格。


按照上面給出的配置,寫好程式:

  1. GPIO_InitTypeDef GPIO_InitStructure;  
  2. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD , ENABLE);  
  3. /* Configure USART Tx as alternate function push-pull */
  4. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
  5. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  
  6. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  7. GPIO_Init(GPIOD, &GPIO_InitStructure);  
  8. /* Configure USART Rx as input floating */
  9. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
  10. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;  
  11. GPIO_Init(GPIOD, &GPIO_InitStructure);  

再次測試,一切正常。

傳送一個字元的函式可以這麼寫:

  1. void UART_PutChar(USART_TypeDef* USARTx, uint8_t Data)  
  2. {  
  3.     while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET ) {};  
  4.     USART_SendData (USARTx, Data);  
  5. }  
這個函式可以手工優化一下,裡面的兩個函式呼叫都可以去掉,甚至於這個函式可以用匯編來實現或者寫成inline 函式。不過這裡只是個示例程式碼,沒有考慮這些。

傳送字串的函式如下:

  1. void UART_PutStr (USART_TypeDef* USARTx, uint8_t *str)  
  2. {  
  3.     while (0 != *str)  
  4.     {  
  5.         UART_PutChar(USARTx, *str);  
  6.         str++;  
  7.     }  
  8. }  

上面串列埠初始化的程式碼可以放到一個函式中:

  1. void USART2_init(void)  
  2. {  
  3.     GPIO_InitTypeDef GPIO_InitStructure;  
  4.     USART_InitTypeDef USART_InitStructure;  
  5.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);  
  6.     /* Configure USART Tx as alternate function push-pull */
  7.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
  8.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  
  9.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  10.     GPIO_Init(GPIOD, &GPIO_InitStructure);  
  11.     /* Configure USART Rx as input floating */
  12.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
  13.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;  
  14.     GPIO_Init(GPIOD, &GPIO_InitStructure);  
  15.     GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);  
  16.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);  
  17.     USART_InitStructure.USART_BaudRate = 9600;  
  18.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;  
  19.     USART_InitStructure.USART_StopBits = USART_StopBits_1;  
  20.     USART_InitStructure.USART_Parity = USART_Parity_No;  
  21.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  22.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  
  23.     USART_Init(USART2, &USART_InitStructure );   
  24.     USART_Cmd(USART2, ENABLE);  
  25. }  

今天先寫這麼多。接收字元的函式與傳送字元的函式差不多,但是這種輪詢方式效率很低,不建議使用。下次寫一篇介紹如何用中斷方式傳送接收串列埠資料,中斷方式的效率會高很多。如果有時間再寫一篇DMA方式傳送接收資料的文章。

相關推薦

STM32F10x USART串列對映功能實現串列通訊 485初始

這篇文章很有用!新手不要自以為是,STM32串列埠管腳重對映小樣你會嗎??? STM32F10x 系列微控制器中都包含了USART 模組,所謂USART,就是通用同步非同步收發器。通用同步非同步收發器(USART)提供了一種靈活的方法與使用工業標準NRZ非同步序列資料格

STM32 USB Virtual COM USB轉串列功能實現

/* USB標準裝置描述符*/ constuint8_tVirtual_Com_Port_DeviceDescriptor[VIRTUAL_COM_PORT_SIZ_DEVICE_DESC]= { 0x12,/*bLength:長度,裝置描述符的長度為18位元組*/ USB_DEVICE_DESC

python實戰串列助手---4實現串列功能

import sysimport threadingimport timeimport serialimport binasciiimport logging class serDeal(object):    def __init__(self, Port="COM4", BaudRate="9600",

無需對映實現外部網路訪問Docker叢集內部服務

注意:讀這篇文章之前最好先看看這個文章  https://blog.csdn.net/czk740960212/article/details/80393825背景Docker支援埠對映,即將主機的某一埠對映到容器的埠,這樣對主機這一埠的請求就會被轉發到容器內,實現外部網路與

內網ip對映外網ip+

 時,先有DNS伺服器將域名翻譯成IP然後再訪問的。在adsl流行的現在,10多個人共用一個IP,那就意味這十多臺電腦中只能存在一臺對外提供網路服務的主機。剩下的通過主機連線上網。要讓剩下的這些機器都對外提供服務,則必須將擁有公網IP的主機接收到的請求轉發到內網的某一臺主機上,這就是埠對映!下面介紹一下埠對映

Nginx80轉發+域名——實現IP+隱藏

一.目的 1.相信大家會遇到這樣的問題:當一臺伺服器部署多個tomcat應用時,當我們訪問tomcat時,需要在瀏覽器中輸入伺服器IP+埠號,這看起來非常的low。 二. 環境 1臺服務伺服器 假如IP:192.168.1.10 一個ngnix 使

通過ssh將mysql伺服器對映到本機

一臺mysql伺服器192.168.1.108因安全問題,未開啟遠端資料訪問,可以通過ssh到服務埠對映到另一臺伺服器192.168.1.188,作為本機埠訪問。 1、在192.168.1.108伺服器上: ssh -R 3306:localhost:3306 [emai

[原創]unity3D學習【功能實現】之三:例項

用處:一般當場景出現兩個及兩個以上,或者會出現重複的物體的時候,用例項化比較方便 目標:滑鼠點選後,在滑鼠點選的位置出現一個小球 涉及到:預製件,Instantiate(預製件,newVector(

(二)SPI通訊初始設定verilog實現

emmmmm,一下子跳到了SPI通訊,跨度有點大,剛好學到這裡,OK少廢話。 相信學過ARM的同學對SPI通訊也有一定的認識,很多模組都需要用到SPI通訊。我就直接用黑金開發板AX301的SPI_Flash例程裡面的SPI_master給大家講解一下。夠良心的啦,黑金開發板

建立一個數組, 實現函式init()初始陣列, 實現empty()清空陣列、,實現reverse()函式完成陣列元素的逆置。自己設計函式的引數,返回值。

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> void init(int arr[], int len) { for (int i = 0; i < len; ++i)

c++ 實現順序棧類(初始,入棧,退棧。讀棧頂元素以及順序輸出棧頂指標與棧中的元素

/* 定義順序棧類(初始化,入棧,退棧。讀棧頂元素以及順序輸出棧頂指標與棧中的元素 */ #include<iostream> using namespace std; // template <class T> class sq_Stack {

redis叢集實現(一)叢集架構與初始

redis是一個高可用、高效能、高可擴充套件性的基於記憶體也支援持久化儲存的kv儲存資料庫,redis相比較於之前的kv儲存memcached而言,不但支援的value型別大大增加,並且還支援資料的持久化,彌補了memcached的不能持久化的缺點,但是在3.0之前的red

stm32f103串列實現對映功能

在實際開發中,經常遇到串列埠的預設輸出IO口被其他模組佔用了,所以我們要用到串列埠IO口對映功能,是指將原來實現功能的IO口對映到其他指定IO口,其他不變。具體操作如下: 先貼出預設下的串列埠初始化設定: void USART1Conf(u32 baudRate) { U

c實現功能(13)實現單向連結串列的簡要功能

#include <stdio.h> #include <stdlib.h> //利用結構體建立節點 struct list{ //建立資料域 int data; //建立指標域 struct list *next; }; //實現建立一個

RTOS_TINY中實現串列傳送字串控制LED

題目內容 在RTOS_TINY作業系統下實現以下目標: 有四個LED,使用AT89S52的4個引腳驅動它們分別以5Hz,8Hz,20Hz,32Hz的頻率閃爍。設使用12MHz的晶振。用串列埠助手,通過傳送 “TURN on 1”,使得LED1持續閃爍,並回顯“LED1 on”;傳送

C++實現串列通訊上位機軟體

串列埠使用的是RS232匯流排進行通訊,通訊方式是半雙工。有兩種方式可以實現串列埠通訊,一種是通過ActiveX控制元件這種方法程式簡單,但欠靈活。第二個是可以通過呼叫Windows的API函式,本例程通過第二種方式。 一般通過四步來完成通訊(1)開啟串列埠(2)配置串列埠(3)讀寫串列埠(4)

【C語言實現串列通訊知識點整理(四)】關於執行緒和程序

轉載:https://www.cnblogs.com/fuchongjundream/p/3829508.html 因為在外部檔案中呼叫結構體沒有用extern修飾,導致獲取不到正確的值,一直糾結線上程上。現在大概總結執行緒和程序的特點: 概念 1、程序(process) 狹義定義:

【C語言實現串列通訊知識點整理(三)】串列開啟、設定資料成功後進行資料讀寫

int OpenDev(char *Dev) { int fd = open(Dev,O_RDWR | O_NOCTTY | O_NONBLOCK); if(-1 == fd) { perror("Can't Open Serial Port"); return -1;

【C語言實現串列通訊知識點整理(二)】遇到的問題整理(待續....)

1.c編譯錯誤--error:stray \357 in program UTF-8編碼問題。UTF-8編碼有BOM和無BOM格式。BOM,ByteOrderMark(位元組標記順序),表明使用UTF8來進行編碼。UTF-8的BOM通常為3個位元組EF BB BF。轉換成對應的字元檢視,就是‘\

【C語言實現串列通訊知識點整理(一)】執行緒、開啟串列、設定波特率、設定校驗位、互斥鎖等實現基本的通訊

  部分程式碼借鑑地址:https://blog.csdn.net/wangqingchuan92/article/details/73497354/ 謝謝! 1.建立執行緒線上程內進行串列埠之間的收發 void CREAT_pthread(void) { pthr