摘要:接收緩沖區和發送緩沖區的請求是獨立的。此時串口實際上還有個字節并未發送完成,數據寄存器和移位寄存器中的個字節還需要發送,并不能關閉串口發送。
串行接口簡稱串口,也稱串行通信接口或串行通訊接口(通常指COM接口),是采用串行通信方式的擴展接口。串行接口(SerialInterface)是指數據一位一位地順序傳送,其特點是通信線路簡單,只要一對傳輸線就可以實現雙向通信(可以直接利用電話線作為傳輸線),從而大大降低了成本,特別適用于遠距離通信,但傳送速度較慢。
USART(universal synchronous asynchronous receiver and transmitte): 通用同步異步收發器
UART(universal asynchronous receiver and transmitter): 通用異步收發器
區別:
USART是指單片機的一個端口模塊,可以根據需要配置成同步模式(SPI,I2C),也可以將其配置為異步模式,后者就是UART。所以說UART姑且可以稱之為一個與SPI,I2C對等的“協議”,而USART則不是一個協議,而是更應該理解為一個實體。
相比于同步通訊,UART不需要統一的時鐘線,接線更加方便。但是,為了正常的對信號進行解碼,使用UART通訊的雙方必須事先約定好波特率,即單位事件內傳輸碼元的個數。
補充:
在電子通信領域,波特(Baud)即調制速率,指的是有效數據訊號調制載波的速率,即單位時間內載波調制狀態變化的次數。它是對符號傳輸速率的一種度量,1波特即指每秒傳輸1個符號,而透過不同的調制方式,可以在一個碼元符號上負載多個bit位信號。[1]“波特”(Baud)本身已是速率,所以不需要寫成 Baud Rate(Rate 是贅字)。單位“波特”本身就已經是代表每秒的調制數,以“波特每秒”(Baud per second)為單位是一種常見的錯誤,但是在一般中文口語化的溝通上還是常以“波特率”來描述“波特”(Baud)。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VkffEvL6-1632828582303)(https://raw.githubusercontent.com/Nepqiu/gallery/master/img/image-20210815155528305.png)]
USART 中斷事件被連接到相同的中斷向量:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IbZhqtpL-1632828582305)(https://raw.githubusercontent.com/Nepqiu/gallery/master/img/image-20210811170712630.png)]
USART 能夠使用 DMA 進行連續通信。接收緩沖區和發送緩沖區的 DMA 請求是獨立的。
使用 DMA 進行發送 將 USART_CR3 寄存器中的 DMAT 位置 1 可以使能 DMA 模式進行發送。當 TXE 位置 1 時,可將數據從 SRAM 區(通過 DMA 配置,參見 DMA 部分)加載到 USART_DR 寄存器。要映射一個 DMA 通道以進行 USART 發送,請按以下步驟操作(x 表示通道編號):
在 DMA 控制寄存器中寫入 USART_DR 寄存器地址,將其配置為傳輸的目標地址。每次發生 TXE 事件后,數據都會從存儲器移動到此地址。
在 DMA 控制寄存器中寫入存儲器地址,將其配置為傳輸的源地址。每次發生 TXE 事件后,數據都會從這個存儲區域加載到 USART_DR 寄存器中。
在 DMA 控制寄存器中配置要傳輸的總字節數。
在 DMA 寄存器中配置通道優先級。
根據應用的需求,在完成一半或全部傳輸后產生 DMA 中斷。
向 SR 寄存器中的 TC 位寫入 0,將其清零。
在 DMA 寄存器中激活該通道。
當達到在 DMA 控制器中設置的數據傳輸量時,DMA 控制器會在 DMA 通道的中斷向量上產生一個中斷。
在發送模式下,DMA 對所有要發送的數據執行了寫操作(DMA_ISR 寄存器中的 TCIF 標志置 1)后,可以對 TC 標志進行監視,以確保 USART 通信已完成。在禁止 USART 或進入停止模式前必須執行此步驟,以避免損壞最后一次發送。軟件必須等待直到 TC=1。TC 標志在所有數據發送期間都必須保持清零狀態,然后在最后一幀發送結束后由硬件置 1。
將 USART_CR3 寄存器中的 DMAR 位置 1 可以使能 DMA 模式進行接收。接收數據字節時,數據會從 USART_DR 寄存器加載到 SRAM 區域中(通過 DMA 配置,參見 DMA 規范)。要映射一個 DMA 通道以進行 USART 接收,請按以下步驟操作:
在 DMA 控制寄存器中寫入 USART_DR 寄存器地址,將其配置為傳輸的源地址。每次發生 RXNE 事件后,數據都會從此地址移動到存儲器。
在 DMA 控制寄存器中寫入存儲器地址,將其配置為傳輸的目標地址。每次發生 RXNE 事件后,數據都會從 USART_DR 寄存器加載到此存儲區。
在 DMA 控制寄存器中配置要傳輸的總字節數。
在 DMA 控制寄存器中配置通道優先級。
根據應用的需求,在完成一半或全部傳輸后產生中斷。
在 DMA 控制寄存器中激活該通道。
當達到在 DMA 控制器中設置的數據傳輸量時,DMA 控制器會在 DMA 通道的中斷向量上產生一個中斷。在中斷子程序中,USART_CR3 寄存器中的 DMAR 位應由軟件清零。
注意: 如果 DMA 用于接收,則不要使能 RXNEIE 位
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NpkQgBln-1632828582308)(https://raw.githubusercontent.com/Nepqiu/gallery/master/img/image-20210811171131932.png)]
多緩沖區通信中的錯誤標志和中斷生成
在多緩沖區通信中,如果事務中發生任何錯誤,都會在當前字節后放置錯誤標志。如果中斷使 能置 1,則會產生中斷。在單字節接收過程中,與 RXNE 一同置位的幀錯誤、上溢錯誤和噪聲 標志具有多帶帶的錯誤標志中斷使能位(USART_CR3 寄存器中的 EIE 位);如果該位置 1, 則會因其中任何一個錯誤而在當前字節后產生中斷。
接收的方式:
發送的方式:
下面主要用 環形隊列+DMA+非動態內存分配+IDLE中斷
建議先看最下面的參考文章
USART1 + DMA + IDLE中斷 +無鎖隊列
int main(void){ uint8_t buff_read[32]; uint32_t length; usart1_init(); while (1) { length = fifo_read_buff(pfifo_x, buff_read, 32); if (length) { printf("lengtt = %d", length); // 實際接收的數據長度 //對接收的數據進行處理 } else { printf("no data rx");// 沒有數據 } if (pfifo_x->error) { printf("fifo error %d", pfifo_x->error);// 接收錯誤 pfifo_x->error = 0; } }}
void USART1_IRQHandler(void) // 接收數據中斷{ __IO uint8_t Len = 0; //發送完成中斷 /* * DMA中斷時,只表示需要傳送的所有數據字節全部傳送到串口的發送數據寄存器中了。 * 此時串口實際上還有2個字節并未發送完成,數據寄存器和移位寄存器中的2個字節還需要發送,并不能關閉串口發送。 * 同理,如果是485切換方向,必須要等到發送完成,也就是移位寄存器發送完成-TC標志置位。 * * TXE指的是發送緩沖器DR空,TC指的是SHIFT移位寄存器空。 * DMA完成只是代表把最后一個字節送到DR寄存器里面了,此時SHIFT移位寄存器有1個字節正在開始發送, * DR寄存器里面有一個字節等待發送,所以就是2個字節未發送完成。 */ if (USART_GetITStatus(USART1, USART_IT_TC) == SET) { USART_ClearITPendingBit(USART1, USART_IT_TC); USART_ITConfig(USART1, USART_IT_TC, DISABLE); DMA2_Stream7_working = 0; } //總線空閑中斷 if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) //觸發中斷標志位 { Len = USART1->SR; //清除RXNE標志 Len = USART1->DR; //清USART_IT_IDLE標志 Len = DMA_GetCurrDataCounter(DMA2_Stream5); //獲取當前剩余數據量大小的函數 if (pfifo_1 != 0) { // Len為當前接收索引 pfifo_1->in += ((pfifo_1->last_cnt - Len) & (pfifo_1->size - 1)); //更新in pfifo_1->last_cnt = Len; if ((pfifo_1->in - pfifo_1->out) > pfifo_1->size) { pfifo_1->out = pfifo_1->in; // 清空緩存,注意賦值順序,pfifo->in = pfifo->out 是錯誤的 pfifo_1->error |= FIFO_DMA_ERROR_RX_FULL; } } else { pfifo_1->error |= FIFO_DMA_ERROR_RX_POINT_NULL; } }}
#define USART1_RX_LEN 32#define USART1_TX_LEN 32uint8_t Usart1_Rx[USART1_RX_LEN] = {0};uint8_t Usart1_Tx[USART1_TX_LEN] = {0};uint8_t Usart1_Tx_Buffer[USART1_TX_LEN] = {0};fifo_rx_def fifo_usart_rx_1;fifo_rx_def *pfifo_1 = &fifo_usart_rx_1;fifo_rx_def fifo_usart_tx_1;uint8_t DMA2_Stream7_working = 0;void usart1_init(void){ /* -------------- Enable Module Clock Source ----------------------------*/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能GPIOA時鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能USART1時鐘 GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); //GPIOA9復用為USART1 GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); //GPIOA10復用為USART1 /* -------------- Configure GPIO ---------------------------------------*/ { GPIO_InitTypeDef GPIO_InitStruct; NVIC_InitTypeDef NVIC_InitStructure; USART_InitTypeDef USART1_InitStruct; //USART1端口配置 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9與GPIOA10 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //復用功能 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽復用輸出 GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOA, &GPIO_InitStruct); //初始化PA9,PA10 //USART1 初始化設置 USART_DeInit(USART1); USART1_InitStruct.USART_BaudRate = 115200; //波特率設置 USART1_InitStruct.USART_WordLength = USART_WordLength_8b; //字長為8位數據格式 USART1_InitStruct.USART_StopBits = USART_StopBits_1; //一個停止位 USART1_InitStruct.USART_Parity = USART_Parity_No; //無奇偶校驗位 USART1_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //無硬件數據流控制 USART1_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發模式 USART_Init(USART1, &USART1_InitStruct); //初始化串口1 USART_Cmd(USART1, ENABLE); //使能串口1 USART_ClearFlag(USART1, USART_FLAG_TC); //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //串口1中斷通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //搶占優先級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根據指定的參數初始化VIC寄存器 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //開啟相關中斷 USART_ITConfig(USART1, USART_IT_TC, DISABLE); USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); } /* -------------- Configure DMA -----------------------------------------*/ /* 發送 */ { DMA_InitTypeDef DMA_InitStruct; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); //發送數據 DMA_Cmd(DMA2_Stream7, DISABLE); //關閉DMA DMA_DeInit(DMA2_Stream7); //重置為缺省值 DMA_InitStruct.DMA_Channel = DMA_Channel_4; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) & (USART1->DR); //源地址 DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)(Usart1_Tx); //目的地址 DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral; //數據傳輸方向為外設到內存 DMA_InitStruct.DMA_BufferSize = USART1_TX_LEN; //設置數據的緩沖大小 DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設地址不變 DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //內存緩沖區地址自加 DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //8位字節傳輸 DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //數據寬度為8位 DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; //工作在正常模式 DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh; //最高優先級 DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream7, &DMA_InitStruct); NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE); //開啟發送完成中斷 DMA_Cmd(DMA2_Stream7, DISABLE); USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); //使能串口的DMA發送 if (fifo_init(&fifo_usart_tx_1, Usart1_Tx_Buffer, USART1_TX_LEN) == -1) { // 必須 2 的冪次方 } } // 接收數據 { DMA_InitTypeDef DMA_InitStruct; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); DMA_Cmd(DMA2_Stream5, DISABLE); //關閉DMA while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE) ; DMA_DeInit(DMA2_Stream5); //重置為缺省值 DMA_InitStruct.DMA_Channel = DMA_Channel_4; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) & (USART1->DR); //源地址 DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)(Usart1_Rx); //目的地址 DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory; //數據傳輸方向為外設到內存 DMA_InitStruct.DMA_BufferSize = USART1_RX_LEN; //設置數據的緩沖大小 DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設地址不變 DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //內存緩沖區地址自加 DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //8位字節傳輸 DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //數據寬度為8位 DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //工作在循環緩存模式 DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh; //最高優先級 DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; DMA_InitStruct.DMA_MemoryBurst = DMA_Mode_Normal; //DMA_MemoryBurst_Single;// DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream5, &DMA_InitStruct); DMA_Cmd(DMA2_Stream5, ENABLE); USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); if (fifo_init(pfifo_1, Usart1_Rx, USART1_RX_LEN) == -1) { // 必須 2 的冪次方 } }}
在設計串口驅動過程中,要遵循的準則是:
void USART1_IRQHandler(void) // 接收數據中斷{ __IO uint8_t Len = 0; //發送完成中斷 /* * DMA中斷時,只表示需要傳送的所有數據字節全部傳送到串口的發送數據寄存器中了。 * 此時串口實際上還有2個字節并未發送完成,數據寄存器和移位寄存器中的2個字節還需要發送,并不能關閉串口發送。 * 同理,如果是485切換方向,必須要等到發送完成,也就是移位寄存器發送完成-TC標志置位。 * * TXE指的是發送緩沖器DR空,TC指的是SHIFT移位寄存器空。 * DMA完成只是代表把最后一個字節送到DR寄存器里面了,此時SHIFT移位寄存器有1個字節正在開始發送, * DR寄存器里面有一個字節等待發送,所以就是2個字節未發送完成。 */ if (USART_GetITStatus(USART1, USART_IT_TC) == SET) { USART_ClearITPendingBit(USART1, USART_IT_TC); USART_ITConfig(USART1, USART_IT_TC, DISABLE); DMA2_Stream7_working = 0; }}
//uint8_t DMA2_Stream7_working = 0;/** * @brief 發送完成中斷 * @param[in] void * @retval void *//* * ST官方都有APPNOTE指導的(對于UART沒有RS485功能的單片機型號而言): * 1、啟動DMA前,先關閉UART發送完成中斷,并清除發送完成中斷標志; * 2、在DMA傳輸完成中斷函數中,開啟UART發送完成中斷; * 3、在UART發送完成中斷函數中,切換RS485為接收態;*/void DMA2_Stream7_IRQHandler(void){ if (DMA_GetITStatus(DMA2_Stream7, DMA_IT_TCIF7) != RESET) { DMA_ClearFlag(DMA2_Stream7, DMA_IT_TCIF7); DMA_Cmd(DMA2_Stream7, DISABLE); //不使能傳輸 //while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); USART_ITConfig(USART1, USART_IT_TC, ENABLE); //DMA2_Stream7_working = 0; }}
//uint8_t DMA2_Stream7_working = 0;/** * @brief 串口一+DMA 發送 * @param[in] *data: 需要發送的數據 * @param[in] len: 數據的大小 * @retval void */uint32_t usart1_dma_send(uint8_t *data, uint16_t len){ uint32_t result = fifo_write_buff(&fifo_usart_tx_1, data, len); //將數據放入循環緩沖區 //result != 0 說明放入數據成功 DMA2_Stream6_working == 0 說明緩沖區里面沒有數據 if (DMA2_Stream7_working == 0 && result != 0) { len = fifo_read_buff(&fifo_usart_tx_1, Usart1_Tx, USART1_TX_LEN); //從循環緩沖區獲取數據 DMA_SetCurrDataCounter(DMA2_Stream7, len); //設定傳輸長度 DMA_Cmd(DMA2_Stream7, ENABLE); //使能傳輸 DMA2_Stream7_working = 1; } if (result == len) { return len; } else { return result; }}
https://www.amobbs.com/thread-4516795-1-1.html
/*指針是指向ptr,需要發送count個數據*/void USART1WriteDataToBuffer(*ptr,u8 count){ /*判斷數據是否發送完畢*/ while(count--) { /*發送數據*/ USART1SendByte(*ptr++); /*等待這個數據發送完畢,然后進入下一個數據的發送過程*/ while(USART_GetFlagStatus(USART1, USART_FLAG_TC); } /*數據發送完畢,返回*/}
這段程序會在實際應用中產生災難性的后果。首先,但發送數據送到寄存器啟動后,CPU就一直在等待這個數據發送完成,這樣,直到所有要發送的數據完成,CPU才能做其他事情。相對于CPU內核運行的速度而言,串口外設的運行速度是非常快的,讓一個非常快的設備去等待相對很慢的設備,程序的效率是非常底下的。
所以盡量采取中斷的方式去發送數據
/*將數據寫入發送緩沖區*/void USART1WriteDataToBuffer(*ptr,u8 count){ while (count != "/0") { USART1SendTCB[Index++] = *ptr++; Count = count; } /***判斷溢出等其他代碼省略***/}/***發送中斷的ISR***/void USART1SendUpdate(void){ /***判斷發送緩沖區中的數據是否發送完畢***/ /***將發送緩沖區的數據發送出去***/ USART1SendByte( *ptr++ ); /***發送指針加一,待發送的字節數減一等代碼***/}
這樣,當調用USART1WriteDataToBuffer
這個函數的時候,我們將要發送的數據寫入發送緩沖區,CPU就可以執行其他任務了,待一個數據發送完成以后,中斷ISR就會觸發,在中斷服務程序中將下一個數據寫入發送寄存器,啟動下一次發送,直到完全發送完畢。
但是在實際工程應用中,經常會遇到這種類似的情況,串口顯示屏需要顯示1000個點,通過串口發送這1000個點的顏色的RGB年度數值。將這1000個數據寫入發送寄存器以后,啟動發送。在115200的波特率,一位起始位,一位停止位,在無校驗位的情況下,至少需要(10*1000*2)/115200=0.1736
秒,在這段期以內,時鐘更新了,需要再發送一串時間更新數據,這個數據大約有100個,這樣這串數據需要寫入到發送緩沖區的發送字節后面。
同樣的道理,在這個時候如果有顯示任務更新的話,將會有其他的數據寫入到緩沖區。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JxeVlfbL-1632828582309)(https://raw.githubusercontent.com/Nepqiu/gallery/master/img/ourdev_611415V21OP9.jpg)]
從圖上可以看出,程序2雖然滿足了時間上的要求,卻沒有滿空間上的要求,它的數據緩沖區的單向的,這樣,當發送緩沖區撐滿了以后才能將發送發送緩沖區的數據清空,以便下次的緩沖數據。這樣內存較小的嵌入式系統來說是不能容忍的。
因此,也可以將發送緩沖區建立一個環形緩沖區,在這個緩沖區內,通過頭指針(HostIndex)和尾指針(HostIndex)來定位空白區和數據區。
這樣就實現了發送緩沖區的動態調整空白區和數據區,剛剛發送完畢的數據,馬上就被開辟出來用于存放下一個數據,最大可能的節省了寶貴的發送緩沖區的空間,提高了效率。
fifo_buff
代碼fifo_buff.c
/** ****************************************************************************** * @file fifo_buff.c/h * @brief 無鎖隊列 * @note * @history 2021.07.08 * @verbatim ============================================================================== 利用 串口+DMA+IDLE中斷+無鎖隊列,提高串口接收效率 (參考《魚鷹談單片機公眾號》) 1、串口初始化函數一旦執行完成,串
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/121488.html
摘要:為了可靠工作,在總線狀態切換時需要做適當延時,再進行數據收發。 一、實現效果 ????????基于ucosii實時操作系統的RS485通信,采用USART + DMA進行收發, ?二、開發環境 開發工具:KEIL V5開發板: STM32f107RC采用方式:USART + DMA使用系統:...
摘要:異步通信與同步通信異步通信異步通信是指通信的發送與接收設備使用各自的時鐘控制數據的發送和接收過程。同步通信同步通信時要建立發送方時鐘對接收方時鐘的直接控制,使雙方達到完全同步。配置串口設置為異步通信基礎參數波特率為。 ...
摘要:芯片內置運算單元,集成了指紋識別算法,能高效快速采集圖像并識別指紋特征。模塊配備了串口通訊接口,用戶無需研究復雜的圖像處理及指紋識別算法,只需通過簡單的串口按照通訊協議便可控制模塊。我們的指紋已經被成功錄入。 目錄 一、硬件使用分類 1.整體圖展示 ?2.STM32F103RCT6單片機 ...
摘要:當單片機要接收數據的時候,控制為低電平,數據通過接收回來。檢測通過萬用表測量控制的引腳一直處于高電平,即使函數就單獨寫將該引腳為低電平,測量出來還是高電平。 一、問題: 問題現象:在進行RS485操作時,發現接收時而進時而不進中斷: 將485的AB輸出腳直接與串口的TX,RX對接發現串...
摘要:通信引腳與連接方式通信數據流動過程需要配置的串口參數與串口相關的的庫函數庫函數初始化串口步驟代碼二超聲波基礎知識前言是利用超聲波特性檢測距離的傳感器。其帶有兩個超聲波探頭,分別用作發射和接收超聲波。 注意!!!!一定要??RCC_APB2PeriphClockCmd(RCC_APB2Peri...
閱讀 826·2021-11-22 11:59
閱讀 3230·2021-11-17 09:33
閱讀 2308·2021-09-29 09:34
閱讀 1941·2021-09-22 15:25
閱讀 1955·2019-08-30 15:55
閱讀 1321·2019-08-30 15:55
閱讀 530·2019-08-30 15:53
閱讀 3346·2019-08-29 13:55