新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STM32 串口功能 庫函數 詳解和DMA 串口高級運用(轉載)

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

        作者: 時間:2016-11-19 來源:網絡 收藏
        數據傳輸時要從支持那些相關的標準?傳輸的速度?什么時候開始?什么時候結束?傳輸的內容?怎樣防止通信出錯?數據量大的時候怎么弄?硬件怎么連接出發,當然對于stm32還要熟悉庫函數的功能

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

        本文引用地址:http://www.104case.com/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("rnSystem Start...rn");
        printf("Initialling SendBuff... rn");
        for(i=0;i{
        SendBuff[i] = i+0;
        }
        printf("Initial success!rnWaiting for transmission...rn");
        //發送去數據已經準備好,按下按鍵即開始傳輸
        while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));

        printf("Start DMA transmission!rn");

        //這里是開始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("rnDMA transmission successful!rn");


        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);
        }



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 文山县| 泗洪县| 天津市| 潜山县| 和林格尔县| 怀柔区| 沁水县| 驻马店市| 炉霍县| 宜君县| 谢通门县| 温泉县| 卢湾区| 娱乐| 鹿泉市| 碌曲县| 涪陵区| 乐安县| 砀山县| 景泰县| 长武县| 卢氏县| 肥东县| 申扎县| 平潭县| 新河县| 沙坪坝区| 孝义市| 赤壁市| 密云县| 淮阳县| 金堂县| 东乡族自治县| 长葛市| 苗栗市| 泊头市| 北宁市| 鄂尔多斯市| 邹城市| 邓州市| 西丰县|