STM32 串口功能 庫函數 詳解和DMA 串口高級運用(轉載)

2020-11-26 電子產品世界
數據傳輸時要從支持那些相關的標準?傳輸的速度?什麼時候開始?什麼時候結束?傳輸的內容?怎樣防止通信出錯?數據量大的時候怎麼弄?硬體怎麼連接出發,當然對於stm32還要熟悉庫函數的功能

具起來rs232和485電平的區別硬體外圍晶片,波特率(反映傳一位的時間),起始位和停止位,數據寬度,校驗,硬體流控制,相應連接電腦時的接口怎麼樣的。配置,使用函數,中斷,查詢並結合通信協議才算了解了串口使用。

本文引用地址:http://www.eepw.com.cn/article/201611/318076.htm

以上是基礎,當然stm很多相關復用功能,支持同步單向通信和半雙工單線通信,支持局部網際網路、智慧卡協議和紅外數據組織相關規範,以及數據機操作,運行多處理器通信。同時可以使用DMA方式進行高速數據通信。注意Print函數時間問題,嘗試通過DMA解決。

特點:全雙工,異步,分數波特率發生器好處是速度快,位數8或9為,可配置1或2停止位,Lin協議,可提供同步時鐘功能。

硬體上

一般2個腳,RX和TX;同步模式需要SCLK時鐘腳,紅外IRDA需要irDA_RDI腳作為數據輸入和irDA_TDO輸出。

奇偶校驗通過usart_cr1pce位配置校驗(發送生成奇偶位,接受時進行校驗)

LIN局域網際網路模式:通過設置USART_CR2中LINEN位配置,使用的時候需要外加專門的收發器才可以

同步模式:通過設置USART_CR2中CLKEN位配置

智慧卡模式:通過設置USART_CR3中SCEN位配置

DMA、硬體流控制作專門研究。

中斷有哪些事件?

發送數據寄存器空發送完成接受數據可讀奇偶校驗錯數據溢出CTS標誌 空閒標誌 斷開標誌 噪聲標誌

遺憾是沒有留有接受緩衝區,用查詢容易數據丟失

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

流程是時鐘配置管腳配置(如重映射,管腳模式)-串口配置-中斷配置--相應中斷--打開串口

上面是一些基礎知識點,下面從實際運用來了解串口功能

比較簡單些的應用吧:對usart進行初始化的工作

void COM1_Init( void)
{

//首先要初始化結構體:少不了對於的引腳,忘不了usart,更牽掛著中斷的配置結構體,定義空間來被塗鴉

GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

//下面是對GPIO進行塗鴉

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//選擇管腳位
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//模式復用推輓輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//選擇管腳位
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//模式為輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);

USART_InitStructure.USART_BaudRate = 115200;//波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8數據位
USART_InitStructure.USART_StopBits = USART_StopBits_1;//1停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無數據流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx USART_Mode_Tx;//收發模式


USART_Init(USART1, &USART_InitStructure);

//使能串口中斷,並設置優先級
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = USART1_IRQn_Priority;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);//將結構體丟到配置函數,即寫入到對應寄存器中


//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

//所有的工作都做好了,最後別忘了打開串口
USART_Cmd(USART1, ENABLE);
}

//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);下面是中斷源

#define USART_IT_PE((uint16_t)0x0028)
#define USART_IT_TXE((uint16_t)0x0727)
#define USART_IT_TC((uint16_t)0x0626)
#define USART_IT_RXNE((uint16_t)0x0525)
#define USART_IT_IDLE((uint16_t)0x0424)
#define USART_IT_LBD((uint16_t)0x0846)
#define USART_IT_CTS((uint16_t)0x096A)
#define USART_IT_ERR((uint16_t)0x0060)
#define USART_IT_ORE((uint16_t)0x0360)
#define USART_IT_NE((uint16_t)0x0260)
#define USART_IT_FE((uint16_t)0x0160)

--

以上是初始化配置,下面還要構成最小的運用,就舉例輸出函數吧

void PrintUart1(const u8 *Str)
{
while(*Str)
{
USART_SendData(USART1, (unsigned char)*Str++);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
}

發送字符是通過查詢字符串的狀態來來不斷的發送下一個數據。

接受數據是通過中斷來實現的,把接受的數據放入緩衝區,來實現。有包含協議以後細講。

想玩電腦串口傳輸數據,通過printf()來直接在電腦窗口顯示是不是很爽?在usart.c函數中加入

//不使用半主機模式
#if 1 //如果沒有這段,則需要在target選項中選擇使用USE microLIB
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
};
FILE __stdout;

_sys_exit(int x)
{
x = x;
}
#endif

int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (unsigned char)ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return ch;
}

上面數據來源可以通過串口,通過usb,通過無線等等。。。

printf函數有個缺陷,就是花費的時間太多了(毫秒級),總不至於讓CPU等幾個毫秒就來顯示串口吧,那再好的CPU也就費了,那腫麼辦?可以用DMA!!直接讓其它硬體來傳這些粗糙的工作。CPU玩重點的其它的活!

先接著講好串口接受,再說這個DMA,在固件庫裡面有個文件是專門用來放中斷處理函數的

裡面有個函數
void USART1_IRQHandler(void)
{
static u8 UartBuf[UART_BUF_LEN];//串口緩衝
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
temp=USART_ReceiveData(USART1);

..............下面就是一些處理,可以用狀態機模式來玩,直到填充好串口緩衝數據,並校驗正確,不多說

}
}

上面是典型的中斷處理函數,結合狀態機功能就強大了。講到作業系統還要進一步的學會運用。

通過上面的學習相信對基本的串口操作有了比較深入的理解了,前面提到printf太慢,這裡需要一些改進。

考慮到真正執行串口輸出(用DMA其實在幾毫秒後完成)比執行完pruntf(立即完成)這個時間點晚個幾毫秒對實際應用來說沒有任何影響,因此CPU可以在嘀嗒中斷中指揮DMA模塊完成串口輸出的任務。(其實對系統還是有些影響的宏觀講,串口輸出的數據其實很少,在大河中放入一杯水,幾乎可以忽略不計的)
再解決怎麼分配:
定義兩個全局緩存區
其中一個緩存區以循環隊列的形式組織,每次執行fputc時向其隊尾加入一個元素。
另一個緩存區直接以數組的形式組織,作為DMA的源地址。
在嘀嗒中斷中按下列順序完成對DMA的操作
(1)判斷循環隊列是否為空,如果為空說明當前沒有字符串需要通過串口輸出直接跳至(6)
(2)判斷DMA是否正在工作,如果DMA正在工作說明上次分配的任何沒幹完直接跳至(6)
(3)從循環隊列出隊N個字符到數組緩存
(4)告訴DMA本次需傳輸的字節數N
(5)命令DMA開始傳輸
(6)結束操作
補充:
1.N的確定方法:若循環隊列中元素的個數大於或等於數組緩存區的長度(固定值),則將數組緩存區的
長度賦給N,若循環隊列中元素的個數小於數組緩存區的長度則將循環隊列元素的個數賦給N
2.循環隊列開闢得越大,能緩存的字符串就越多,因此是越大越好.
3.數組緩存區並不是開闢的越大越好,這個值可以做如下的計算得出,假設波特率為115200嘀嗒中斷
的周期為2毫秒則在這2毫秒時間內理論上最多可傳115200*0.002/10=23個字節。因此把數組緩存區
的大小定到比23稍小一點即可,比如定為20.
代碼可正常運行。經測試使用新方案printf一個包含了二十個字符的字符串只需要25微秒的CPU耗時,
而老方案則需要1.76毫秒的CPU耗時。從而可以放心的使用printf調試一些時序要求較高的函數了,
另外因為執行時間段從而printf被重入的概率大大減小。如果需要徹底防止printf被重入的話,可在調用printf之前關中斷,在printf執行完之後開中斷,代價也僅是可能發生的幾十微秒的中斷延時而已。

.........................................................................................

下面講一講我對DMA的理解

stm32DMA有8通道,07

既然DMA傳輸的是數據,當然有數據的寬度了,這需要配置。另外還要有地址吧,從哪個地址開始傳,還有傳到哪個地址,需要配置。還有傳輸普通的就直接傳完就好了,如果要高速不斷循環傳輸,這也可以配置。還有從ROM直接快速的加載到RAM(反過來不可以)也可以的。

之上就是一些基本需要配置的工作

DMA_DeInit(DMA1_Channel4);

上面這句是給DMA配置通道,根據ST提供的資料,STM3210Fx中DMA包含7個通道

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&((USART_TypeDef *)USART1)->DR);
上面是設置外設地址

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) USART_DMA_BUF;

上面這句很顯然是DMA要連接在Memory中變量的地址,上面設置存儲器地址;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

上面的這句是設置DMA的傳輸方向,就如前面我所說的,從存儲器到外設,也可以從外設到存儲器,:把DMA_DIR_PeripheralSRC改成DMA_DIR_PeripheralDST即可。

DMA_InitStructure.DMA_BufferSize = 0;

上面的這句是設置DMA在傳輸時緩衝區的長度,前面有定義過了buffer的起始地址:為了安全性和可靠性,一般需要給buffer定義一個儲存片區,這個參數的單位有三種類型:Byte、HalfWord、word,我設置的2個half-word(見下面的設置);32位的MCU中1個half-word佔16 bits。

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

上面的這句是設置DMA的外設遞增模式,如果DMA選用的通道(CHx)有多個外設連接,需要使用外設遞增模式:DMA_PeripheralInc_Enable;我的例子選用DMA_PeripheralInc_Disable

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

上面的這句是設置DMA的內存遞增模式,DMA訪問多個內存參數時,需要使用DMA_MemoryInc_Enable,當DMA只訪問一個內存參數時,可設置成:DMA_MemoryInc_Disable。

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

上面的這句是設置DMA在訪問時每次操作的數據長度。有三種數據長度類型,前面已經講過了,這裡不在敘述。

DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;

與上面雷同。在此不再說明。

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

上面的這句是設置DMA的傳輸模式:連續不斷的循環模式,若只想訪問一次後就不要訪問了(或按指令操作來反問,也就是想要它訪問的時候就訪問,不要它訪問的時候就停止),可以設置成通用模式:DMA_Mode_Normal

DMA_InitStructure.DMA_Priority = DMA_Priority_Low;

上面的這句是設置DMA的優先級別:可以分為4級:VeryHigh,High,Medium,Low.

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

上面的這句是設置DMA的2個memory中的變量互相訪問的

DMA_Init(DMA_Channel1,&DMA_InitStructure);

前面那些都是對DMA結構體成員的設置,在次再統一對DMA整個模塊做一次初始化,使得DMA各成員與上面的參數一致。

DMA_Cmd(DMA_Channel1,ENABLE);

ok上面的配置工作完成了,相當於設定了一根管道通過DMA把緩衝區中要發送的數據發送到串口中。當然要使得DMA與usart1相連接,在usart1中還要把usart的DMA功能打開:USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);接著在程序中只需要監控,數據發送的狀態,並適時的打開或關閉DMA,留著下一次的串口發送用。

函數重載的printf()函數如下

int fputc(int ch, FILE *f)
{
while(En_Usart_Queue(ch)==-1);
return ch;
}

起始就是往環形緩衝區中添加要串口列印的數據,這個動作是比較快的。因為cpu直接移動數據很快,而通過cpu來操作串口,等待收穫反映,有個while(..)是比較慢得,故有幾個毫秒的延時。現在好了,cpu ,通過printf只是移動數據到了緩衝區,緩衝區在一定的時候,cpu指揮dma來開始接下來的操作,然後dma操作,cpu接著做其他的事情,僅僅只要在下次空閒的時候來查一下dma有木有傳輸完成,或者有沒有傳輸錯誤,並改變環形隊列首位的位置,以及更改相應的狀態就可以了。這樣可以大大的節省很多的時間哦。
環形隊列的結構,大家可以看一些算法,不是很難的。

下面是運行過程中,cpu操作查詢的函數。

void DMA_USART_Handler(void){
u16 num=0;
s16 read;
if(DMA_GetCurrDataCounter(DMA1_Channel4)==0){ //檢查DMA是否完成傳輸任務
DMA_Cmd(DMA1_Channel4, DISABLE);
while((read=De_Usart_Queue())!=-1){
USART_DMA_BUF[num]=read;
num++;
if(num==USART_DMA_BUF_SIZE)
break;
}
if(num>0){
((DMA_Channel_TypeDef *)DMA1_Channel4)->CNDTR = num;//數量寄存器清零
DMA_Cmd(DMA1_Channel4, ENABLE);
}
}
}

一.DMA原理:

DMA(Direct Memory Access,直接內存存取) 是所有現代電腦的重要特色,它允許不同速度的硬體裝置來溝通,而不需要依於 CPU 的大量 中斷 負載。否則,CPU 需要從 來源 把每一片段的資料到 暫存器,然後把它們再次寫回到新的地方。在這個時間中,CPU 對於其他的工作來說就無法使用。

DMA 傳輸將數據從一個地址空間到另外一個地址空間。當 CPU 初始化這個傳輸動作,傳輸動作本身是由 DMA 控制器 來實行和完成。典型的例子就是移動一個外部內存的區塊到晶片內部更快的內存區。像是這樣的操作並沒有讓處理器工作拖延,反而可以被重新排程去處理其他的工作。

二.STM32使用DMA

1.DMA的設置:

要配置的有DMA傳輸通道選擇,傳輸的成員和方向、普通模式還是循環模式等等。

void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
//DMA設置:
//設置DMA源:內存地址&串口數據寄存器地址
//方向:內存-->外設
//每次傳輸位:8bit
//傳輸大小DMA_BufferSize=SENDBUFF_SIZE
//地址自增模式:外設地址不增,內存地址自增1
//DMA模式:一次傳輸,非循環
//優先級:中
DMA_DeInit(DMA1_Channel4);//串口1的DMA傳輸通道是通道4
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr =(u32)SendBuff;//DMA訪問的數據地址
DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralDST;//外設作為DMA的目的端
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//傳輸數據大小
DMA_InitStructure.DMA_PeripheralInc =DMA_PeripheralInc_Disable;//外設地址不增加
DMA_InitStructure.DMA_MemoryInc =DMA_MemoryInc_Enable;//內存地址自增1
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode =DMA_Mode_Circular;

//DMA_Mode_Normal(只傳送一次),DMA_Mode_Circular (循環傳送)
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA傳送優先級為中等)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}

註:

1、傳輸通道:通過查表,串口1的發送對應的是DMA的通道4,所以此處選擇通道4.

2、DMA傳輸方式:

(1) DMA_Mode_Normal,正常模式,當一次DMA數據傳輸完後,停止DMA傳送,對於上例而言,就是DMA_PeripheralDataSize_Byte個字節的傳送完成後,就停止傳送。

(2)DMA_Mode_Circular

循環模式,當傳輸完一次後,重新接著傳送,永不停息。

2、外設的DMA方式設置

將串口1設置成DMA模式:

USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

3、待傳輸數據的定義和初始化

#define SENDBUFF_SIZE10240
vu8 SendBuff[SENDBUFF_SIZE];

for(i=0;i{
SendBuff[i] = i+0;
}
4、開始DMA傳輸(使能對應的DMA通道)
DMA_Cmd(DMA1_Channel4, ENABLE);

5、DMA傳輸的完成

while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
LED_1_REV;//LED改變亮滅
Delay();//浪費時間
}

當傳輸完成後,就會跳出上面的死循環。

下面是九九的一個例程,測試過,可以運行!


#include "stm32f10x_lib.h"
#include "stdio.h"



#define USART1_DR_Base0x40013804



#define SENDBUFF_SIZE10240
vu8 SendBuff[SENDBUFF_SIZE];
vu8 RecvBuff[10];
vu8 recv_ptr;


void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void DMA_Configuration(void);
void USART1_Configuration(void);

int fputc(int ch, FILE *f);
void Delay(void);



int main(void)
{
u16 i;
#ifdef DEBUG
debug();
#endif
recv_ptr = 0;

RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
DMA_Configuration();
USART1_Configuration();

printf("\r\nSystem Start...\r\n");
printf("Initialling SendBuff... \r\n");
for(i=0;i{
SendBuff[i] = i+0;
}
printf("Initial success!\r\nWaiting for transmission...\r\n");
//發送去數據已經準備好,按下按鍵即開始傳輸
while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));

printf("Start DMA transmission!\r\n");

//這裡是開始DMA傳輸前的一些準備工作,將USART1模塊設置成DMA方式工作
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
//開始一次DMA傳輸!
DMA_Cmd(DMA1_Channel4, ENABLE);

//等待DMA傳輸完成,此時我們來做另外一些事,點燈
//實際應用中,傳輸數據期間,可以執行另外的任務
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
Delay();//浪費時間
}
//DMA傳輸結束後,自動關閉了DMA通道,而無需手動關閉
//下面的語句被注釋
//DMA_Cmd(DMA1_Channel4, DISABLE);

printf("\r\nDMA transmission successful!\r\n");



while (1)
{
}
}


int fputc(int ch, FILE *f)
{
//USART_SendData(USART1, (u8) ch);
USART1->DR = (u8) ch;


while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{
}

return ch;
}


void Delay(void)
{
u32 i;
for(i=0;i<0xF0;i++);
return;
}


void RCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus;

//使能外部晶振
RCC_HSEConfig(RCC_HSE_ON);
//等待外部晶振穩定
HSEStartUpStatus = RCC_WaitForHSEStartUp();
//如果外部晶振啟動成功,則進行下一步操作
if(HSEStartUpStatus==SUCCESS)
{
//設置HCLK(AHB時鐘)=SYSCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1);

//PCLK1(APB1) = HCLK/2
RCC_PCLK1Config(RCC_HCLK_Div2);

//PCLK2(APB2) = HCLK
RCC_PCLK2Config(RCC_HCLK_Div1);

//FLASH時序控制
//推薦值:SYSCLK = 0~24MHzLatency=0
//SYSCLK = 24~48MHzLatency=1
//SYSCLK = 48~72MHzLatency=2
FLASH_SetLatency(FLASH_Latency_2);
//開啟FLASH預取指功能
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

//PLL設置 SYSCLK/1 * 9 = 8*1*9 = 72MHz
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//啟動PLL
RCC_PLLCmd(ENABLE);
//等待PLL穩定
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
//系統時鐘SYSCLK來自PLL輸出
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//切換時鐘後等待系統時鐘穩定
while(RCC_GetSYSCLKSource()!=0x08);



}

//下面是給各模塊開啟時鐘
//啟動GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA RCC_APB2Periph_GPIOB \
RCC_APB2Periph_GPIOC RCC_APB2Periph_GPIOD,\
ENABLE);
//啟動AFIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//啟動USART1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//啟動DMA時鐘
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

}


void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

//PC口4567腳設置GPIO輸出,推挽 2M
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 GPIO_Pin_5 GPIO_Pin_6 GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);

//KEY2 KEY3 JOYKEY
//位於PD口的3 4 11-15腳,使能設置為輸入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 GPIO_Pin_4 GPIO_Pin_11 GPIO_Pin_12 \
GPIO_Pin_13 GPIO_Pin_14 GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);

//USART1_TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//USART1_RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);

}


void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;

#ifdefVECT_TAB_RAM
// Set the Vector Table base location at 0x20
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
// Set the Vector Table base location at 0x08
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif

//設置NVIC優先級分組為Group2:0-3搶佔式優先級,0-3的響應式優先級
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//串口接收中斷打開
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}



void USART1_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;

USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

USART_Cmd(USART1, ENABLE);
}


void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
//DMA設置:
//設置DMA源:內存地址&串口數據寄存器地址
//方向:內存-->外設
//每次傳輸位:8bit
//傳輸大小DMA_BufferSize=SENDBUFF_SIZE
//地址自增模式:外設地址不增,內存地址自增1
//DMA模式:一次傳輸,非循環
//優先級:中
DMA_DeInit(DMA1_Channel4);//串口1的DMA傳輸通道是通道4
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外設作為DMA的目的端
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//傳輸大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外設地址不增加
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//內存地址自增1
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Normal(只傳送一次),DMA_Mode_Circular (不停地傳送)
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA傳送優先級為中等)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}


相關焦點

  • Arduino的串口通訊函數
    這時候就需要依靠強大的Arduino庫函數,比如我們前面所說的 Serial.begin(9600)、delay(1000)等都是庫函數,我們可以直接調用,而無需知道他的原始碼。依靠庫函數可以看到我們發送數據時應有的現象,比如說我們給Arduino發送1,當Arduino收到1之後點亮LED,而收到0之後熄滅LED。
  • 什麼是「串口」?
    這時需要串口的握手功能。在這一部分,我們討論三種最常用的RS-232握手形式:軟體握手、硬體握手和Xmodem。a,軟體握手:我們討論的第一種握手是軟體握手。通常用在實際數據是控制字符的情況,類似於GPIB使用命令字符串的方式。
  • LabVIEW串口通信的一個例子-串口"示波器"
    功能介紹:左邊上方串口接收區,下方為串口字符發送區。右方為一個波形圖表,在程序內部每次將串口發送過來的數據,以f%格式化,顯示在波形圖表上。VI將等待 發表於 2020-11-25 labview圖形和圖表的類型 LabVIEW包含以下類型的圖形和圖表:波形圖和圖表-顯示採樣率恆定的數據。XY圖-顯示採樣率非均勻的數據及多值函數的數據。
  • 串口通信原理和控制程序
    以USART1為例的串口初始化本文引用地址:http://www.eepw.com.cn/article/201809/391492.htm  本程序調用了STM32自帶的固件庫,工程中具體的文件見下圖:
  • python3腳本篇1-串口通訊腳本
    前言本文我們來學習Python軟體包pyserial的使用,硬體採用wemos D1開發板,直接燒錄串口章節代碼即可,本文主要編寫PC端Python腳本,完成腳本和外接串口設備通訊的功能。一、基礎知識1.pyserial簡介:pyserial模塊是python和串口設備通訊的package,串口是計算機上比較通用的通訊協議,串口設備通過USB插入電腦,python通過pyserial模塊就可以完成和串口設備的通訊,
  • 中標麒麟作業系統串口調試方法研究
    目前,由於國產的中標麒麟作業系統有著高安全性,以及其功能、穩定性、效率方面都達到國外同類產品水平,部分指標還要優於國外同類產品,極大地降低了採購成本及維護成本等特點,中標麒麟作業系統逐步地應用到了部隊、國家大型的建設項目、企事業單位中,如國家電網D5000項目等[1]。串口作為一種廣泛應用的計算機接口,計算機對設備進行通信控制幾乎都是通過串口進行的。
  • 串口轉乙太網實現了TCP/IP的嵌入式協議轉換
    串口轉乙太網模塊是嵌入式設備、單片機和物聯網採集系統基於TCP/IP協議接入網絡的一種方便、穩定的解決方案。 串口轉乙太網通信: 串口伺服器提供串口轉網絡功能,可以將RS232/485/422串口轉換成TCP/IP網絡接口,實現RS232/485/422串口與TCP/IP網絡接口之間的雙向透明數據傳輸。因此,串行設備可以立即具備TCP/IP網絡接口功能,連接到網絡進行數據通信,大大擴展了串行設備的通信距離。
  • GPIO相關寄存器配置詳解
    ----------------------------------------------------------------------------------------------------------------------------------注意:如果在配置IO的寄存器前一定要先配置時鐘的寄存器,與庫函數版本一樣
  • 一分四串口UART擴展晶片的特性
    SPI轉串口(UART)一分四 MAX14830是Maxim公司的一款四通道通用異步收發器(UART),每路UART帶有128字先入/先出(FIFO)接收和發送緩存器,以及高速串行外設接口(SPI™)或I²C控制器接口。PLL和分數波特率發生器為波特率編程和參考時鐘選擇提供了極大靈活性。
  • 基於MFC串口連續通信的簡易實現
    之間的時間間隔T1,將間隔本文引用地址:http://www.eepw.com.cn/article/201610/306451.htm串口通信適用於長距離控制與數據傳輸,許多單片機在內部均集成了串口通信模塊,而計算機的作業系統也內嵌有對串口通信的支持。
  • 基於C8051F040單片機的CAN總線和RS-232串口通信設計
    為了實現對CAN總線和RS-232串口雙向通信需求,提出了一種基於C8051F040單片機的數據通信方案,並完成系統設計。分析了CAN總線和RS-232串口的通信特點,介紹了單片機硬體,並對軟體的設計思路與流程做了詳盡描述,完成功能檢測。實驗結果表明,該設計達到了要求。
  • 怎麼學習STM32單片機?看老司機是怎麼說的!
    你問,如何系統地入門學習stm32?  本身就是一個錯誤的問題。假如你會使用8051 , 會寫C語言,那麼STM32本身並不需要刻意的學習。  你要考慮的是, 我可以用STM32實現什麼?  為什麼使用STM32而不是8051? 是因為51的頻率太低,無法滿足計算需求?
  • stm32編碼器的接口模式
    編碼器是什麼玩意呢,它可是一個好玩的東西,做小車測速必不可少的玩意,下面,我將從編碼器的原理講起,一直到用stm32的編碼器接口模式,測出電機轉速與方向。2.stm32編碼器接口模式(寄存器)        stm32的編碼器接口模式在STM32中文參考手冊中有詳細的說明,在手冊273頁,14.3.12節。程序是完全按照 下圖方式,設置寄存器的。
  • avr單片機和stm32區別與優缺點分析
    摘要:avr單片機和stm32單片機是目前使用較廣泛的單片機,那麼avr單片機和stm32單片機有什麼區別呢?有什麼優劣勢呢?   串口使用一個max232晶片。   使用跳線JMP2—1,不使用串口時,請將其斷開,防止串口電路對IO口的幹擾。
  • arduino設置串口模式專題及常見問題 - CSDN
    模擬信號輸出函數 (基於DAC)ESP32提供了兩個DAC通道, 對應引腳25 , 26. 精度為8位.串口名Arduino名TXRXUART0Serialpin1pin3UART1Serial1pin10pin9UART2Serial2pin17pin161、串口初始化Serial.begin(speed, config)參數:speed:波特率,一般取值9600,115200等。config:設置數據位、校驗位和停止位。
  • 從串口驅動到Linux驅動模型,想轉Linux的必會!
    本文通過對Linux下串口驅動的分析。由最上層的C庫。到作業系統系統調用層的封裝。再到tty子系統的核心。再到一系列線路規程。再到最底層的硬體操作。對Linux中的tty子系統進行簡要的說明。從理論到實踐。以便讀者能對OS原理有更深入的了解和更具體的掌握。在具體分析之前。我們必須對串口。驅動。和Linux作業系統有一定的了解。
  • 淺談硬體串口通信基礎概念
    串口通信(Serial Communication),是指外設和計算機間通過數據信號線、地線等按位進行傳輸數據的一種通信方式,屬於串行通信方式。串口是一種接口標準,它規定了接口的電氣標準,沒有規定接口插件電纜以及使用的協議。
  • 串口波特率轉換的純軟體實現
    本軟體用Visual Basic軟體編寫,串口用MSCOMM控制項實現。核心功能就是將Mscomm1接收的數據立即送到Mscomm2的發送區。難點在於對16進位數據的轉換處理。 On Error GoTo uerror3 MSComm2.Output = strBuff Label14.Caption = Label14.Caption + Len(strBuff) 發送計數 End If End Selectuerror3:End Sub本文介紹的串口波特率轉換的純軟體方法和程序
  • RS-232-C串口、串口線的使用說明
    串口按接口來分類的話,有RS-232、RS-422和RS-485幾種,其中RS-232串口是最常用的一種串行通訊接口,也稱標準串口。其全名是「數據終端設備(DTE)和數據通訊設備(DCE)之間串行二進位數據交換接口技術標準」。
  • 基於串口通訊技術實現流量計計量系統的設計
    為達到工業環境對高可靠性產品的要求,此產品提供可選擇的光電隔離(2 KV)和浪湧保護(25KV ESD)功能。並且內建終端電阻,可以方便地應用在遠程通訊中。此串口卡被廣泛地應用於:多點數據採集;工廠自動化、遠程串口設備控制、工業控制、嵌入式工業機械和SCADA 系統。