<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > STM32 串口功能 庫(kù)函數(shù) 詳解和DMA 串口高級(jí)運(yùn)用(轉(zhuǎn)載)

          STM32 串口功能 庫(kù)函數(shù) 詳解和DMA 串口高級(jí)運(yùn)用(轉(zhuǎn)載)

          作者: 時(shí)間:2016-11-19 來(lái)源:網(wǎng)絡(luò) 收藏
          數(shù)據(jù)傳輸時(shí)要從支持那些相關(guān)的標(biāo)準(zhǔn)?傳輸?shù)乃俣??什么時(shí)候開始?什么時(shí)候結(jié)束?傳輸?shù)膬?nèi)容?怎樣防止通信出錯(cuò)?數(shù)據(jù)量大的時(shí)候怎么弄?硬件怎么連接出發(fā),當(dāng)然對(duì)于stm32還要熟悉庫(kù)函數(shù)的功能

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

          本文引用地址:http://www.ex-cimer.com/article/201611/318076.htm

          以上是基礎(chǔ),當(dāng)然stm很多相關(guān)復(fù)用功能,支持同步單向通信和半雙工單線通信,支持局部互聯(lián)網(wǎng)、智能卡協(xié)議和紅外數(shù)據(jù)組織相關(guān)規(guī)范,以及調(diào)制解調(diào)器操作,運(yùn)行多處理器通信。同時(shí)可以使用DMA方式進(jìn)行高速數(shù)據(jù)通信。注意Print函數(shù)時(shí)間問(wèn)題,嘗試通過(guò)DMA解決。

          特點(diǎn):全雙工,異步,分?jǐn)?shù)波特率發(fā)生器好處是速度快,位數(shù)8或9為,可配置1或2停止位,Lin協(xié)議,可提供同步時(shí)鐘功能。

          硬件上

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

          奇偶校驗(yàn)通過(guò)usart_cr1pce位配置校驗(yàn)(發(fā)送生成奇偶位,接受時(shí)進(jìn)行校驗(yàn))

          LIN局域互聯(lián)網(wǎng)模式:通過(guò)設(shè)置USART_CR2中LINEN位配置,使用的時(shí)候需要外加專門的收發(fā)器才可以

          同步模式:通過(guò)設(shè)置USART_CR2中CLKEN位配置

          智能卡模式:通過(guò)設(shè)置USART_CR3中SCEN位配置

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

          中斷有哪些事件?

          發(fā)送數(shù)據(jù)寄存器空發(fā)送完成接受數(shù)據(jù)可讀奇偶校驗(yàn)錯(cuò)數(shù)據(jù)溢出CTS標(biāo)志 空閑標(biāo)志 斷開標(biāo)志 噪聲標(biāo)志

          遺憾是沒(méi)有留有接受緩沖區(qū),用查詢?nèi)菀讛?shù)據(jù)丟失

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

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

          上面是一些基礎(chǔ)知識(shí)點(diǎn),下面從實(shí)際運(yùn)用來(lái)了解串口功能

          比較簡(jiǎn)單些的應(yīng)用吧:對(duì)usart進(jìn)行初始化的工作

          void COM1_Init( void)
          {

          //首先要初始化結(jié)構(gòu)體:少不了對(duì)于的引腳,忘不了usart,更牽掛著中斷的配置結(jié)構(gòu)體,定義空間來(lái)被涂鴉

          GPIO_InitTypeDef GPIO_InitStructure;
          USART_InitTypeDef USART_InitStructure;
          NVIC_InitTypeDef NVIC_InitStructure;

          //下面是對(duì)GPIO進(jìn)行涂鴉

          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;//模式復(fù)用推挽輸出
          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數(shù)據(jù)位
          USART_InitStructure.USART_StopBits = USART_StopBits_1;//1停止位
          USART_InitStructure.USART_Parity = USART_Parity_No;//無(wú)奇偶校驗(yàn)
          USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無(wú)數(shù)據(jù)流控制
          USART_InitStructure.USART_Mode = USART_Mode_Rx USART_Mode_Tx;//收發(fā)模式


          USART_Init(USART1, &USART_InitStructure);

          //使能串口中斷,并設(shè)置優(yōu)先級(jí)
          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);//將結(jié)構(gòu)體丟到配置函數(shù),即寫入到對(duì)應(yīng)寄存器中


          //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)

          --

          以上是初始化配置,下面還要構(gòu)成最小的運(yùn)用,就舉例輸出函數(shù)吧

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

          發(fā)送字符是通過(guò)查詢字符串的狀態(tài)來(lái)來(lái)不斷的發(fā)送下一個(gè)數(shù)據(jù)。

          接受數(shù)據(jù)是通過(guò)中斷來(lái)實(shí)現(xiàn)的,把接受的數(shù)據(jù)放入緩沖區(qū),來(lái)實(shí)現(xiàn)。有包含協(xié)議以后細(xì)講。

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

          //不使用半主機(jī)模式
          #if 1 //如果沒(méi)有這段,則需要在target選項(xiàng)中選擇使用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;
          }

          上面數(shù)據(jù)來(lái)源可以通過(guò)串口,通過(guò)usb,通過(guò)無(wú)線等等。。。

          printf函數(shù)有個(gè)缺陷,就是花費(fèi)的時(shí)間太多了(毫秒級(jí)),總不至于讓CPU等幾個(gè)毫秒就來(lái)顯示串口吧,那再好的CPU也就費(fèi)了,那腫么辦?可以用DMA!!直接讓其它硬件來(lái)傳這些粗糙的工作。CPU玩重點(diǎn)的其它的活!

          先接著講好串口接受,再說(shuō)這個(gè)DMA,在固件庫(kù)里面有個(gè)文件是專門用來(lái)放中斷處理函數(shù)的

          里面有個(gè)函數(shù)
          void USART1_IRQHandler(void)
          {
          static u8 UartBuf[UART_BUF_LEN];//串口緩沖
          if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
          {
          temp=USART_ReceiveData(USART1);

          ..............下面就是一些處理,可以用狀態(tài)機(jī)模式來(lái)玩,直到填充好串口緩沖數(shù)據(jù),并校驗(yàn)正確,不多說(shuō)

          }
          }

          上面是典型的中斷處理函數(shù),結(jié)合狀態(tài)機(jī)功能就強(qiáng)大了。講到操作系統(tǒng)還要進(jìn)一步的學(xué)會(huì)運(yùn)用。

          通過(guò)上面的學(xué)習(xí)相信對(duì)基本的串口操作有了比較深入的理解了,前面提到printf太慢,這里需要一些改進(jìn)。

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

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

          下面講一講我對(duì)DMA的理解

          stm32DMA有8通道,07

          既然DMA傳輸?shù)氖菙?shù)據(jù),當(dāng)然有數(shù)據(jù)的寬度了,這需要配置。另外還要有地址吧,從哪個(gè)地址開始傳,還有傳到哪個(gè)地址,需要配置。還有傳輸普通的就直接傳完就好了,如果要高速不斷循環(huán)傳輸,這也可以配置。還有從ROM直接快速的加載到RAM(反過(guò)來(lái)不可以)也可以的。

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

          DMA_DeInit(DMA1_Channel4);

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

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

          DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) USART_DMA_BUF;

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

          DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

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

          DMA_InitStructure.DMA_BufferSize = 0;

          上面的這句是設(shè)置DMA在傳輸時(shí)緩沖區(qū)的長(zhǎng)度,前面有定義過(guò)了buffer的起始地址:為了安全性和可靠性,一般需要給buffer定義一個(gè)儲(chǔ)存片區(qū),這個(gè)參數(shù)的單位有三種類型:Byte、HalfWord、word,我設(shè)置的2個(gè)half-word(見(jiàn)下面的設(shè)置);32位的MCU中1個(gè)half-word占16 bits。

          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

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

          DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

          上面的這句是設(shè)置DMA的內(nèi)存遞增模式,DMA訪問(wèn)多個(gè)內(nèi)存參數(shù)時(shí),需要使用DMA_MemoryInc_Enable,當(dāng)DMA只訪問(wèn)一個(gè)內(nèi)存參數(shù)時(shí),可設(shè)置成:DMA_MemoryInc_Disable。

          DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

          上面的這句是設(shè)置DMA在訪問(wèn)時(shí)每次操作的數(shù)據(jù)長(zhǎng)度。有三種數(shù)據(jù)長(zhǎng)度類型,前面已經(jīng)講過(guò)了,這里不在敘述。

          DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;

          與上面雷同。在此不再說(shuō)明。

          DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

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

          DMA_InitStructure.DMA_Priority = DMA_Priority_Low;

          上面的這句是設(shè)置DMA的優(yōu)先級(jí)別:可以分為4級(jí):VeryHigh,High,Medium,Low.

          DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

          上面的這句是設(shè)置DMA的2個(gè)memory中的變量互相訪問(wèn)的

          DMA_Init(DMA_Channel1,&DMA_InitStructure);

          前面那些都是對(duì)DMA結(jié)構(gòu)體成員的設(shè)置,在次再統(tǒng)一對(duì)DMA整個(gè)模塊做一次初始化,使得DMA各成員與上面的參數(shù)一致。

          DMA_Cmd(DMA_Channel1,ENABLE);

          ok上面的配置工作完成了,相當(dāng)于設(shè)定了一根管道通過(guò)DMA把緩沖區(qū)中要發(fā)送的數(shù)據(jù)發(fā)送到串口中。當(dāng)然要使得DMA與usart1相連接,在usart1中還要把usart的DMA功能打開:USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);接著在程序中只需要監(jiān)控,數(shù)據(jù)發(fā)送的狀態(tài),并適時(shí)的打開或關(guān)閉DMA,留著下一次的串口發(fā)送用。

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

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

          起始就是往環(huán)形緩沖區(qū)中添加要串口打印的數(shù)據(jù),這個(gè)動(dòng)作是比較快的。因?yàn)閏pu直接移動(dòng)數(shù)據(jù)很快,而通過(guò)cpu來(lái)操作串口,等待收獲反映,有個(gè)while(..)是比較慢得,故有幾個(gè)毫秒的延時(shí)?,F(xiàn)在好了,cpu ,通過(guò)printf只是移動(dòng)數(shù)據(jù)到了緩沖區(qū),緩沖區(qū)在一定的時(shí)候,cpu指揮dma來(lái)開始接下來(lái)的操作,然后dma操作,cpu接著做其他的事情,僅僅只要在下次空閑的時(shí)候來(lái)查一下dma有木有傳輸完成,或者有沒(méi)有傳輸錯(cuò)誤,并改變環(huán)形隊(duì)列首位的位置,以及更改相應(yīng)的狀態(tài)就可以了。這樣可以大大的節(jié)省很多的時(shí)間哦。
          環(huán)形隊(duì)列的結(jié)構(gòu),大家可以看一些算法,不是很難的。

          下面是運(yùn)行過(guò)程中,cpu操作查詢的函數(shù)。

          void DMA_USART_Handler(void){
          u16 num=0;
          s16 read;
          if(DMA_GetCurrDataCounter(DMA1_Channel4)==0){ //檢查DMA是否完成傳輸任務(wù)
          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;//數(shù)量寄存器清零
          DMA_Cmd(DMA1_Channel4, ENABLE);
          }
          }
          }

          一.DMA原理:

          DMA(Direct Memory Access,直接內(nèi)存存取) 是所有現(xiàn)代電腦的重要特色,它允許不同速度的硬件裝置來(lái)溝通,而不需要依于 CPU 的大量 中斷 負(fù)載。否則,CPU 需要從 來(lái)源 把每一片段的資料到 暫存器,然后把它們?cè)俅螌懟氐叫碌牡胤?。在這個(gè)時(shí)間中,CPU 對(duì)于其他的工作來(lái)說(shuō)就無(wú)法使用。

          DMA 傳輸將數(shù)據(jù)從一個(gè)地址空間到另外一個(gè)地址空間。當(dāng) CPU 初始化這個(gè)傳輸動(dòng)作,傳輸動(dòng)作本身是由 DMA 控制器 來(lái)實(shí)行和完成。典型的例子就是移動(dòng)一個(gè)外部?jī)?nèi)存的區(qū)塊到芯片內(nèi)部更快的內(nèi)存區(qū)。像是這樣的操作并沒(méi)有讓處理器工作拖延,反而可以被重新排程去處理其他的工作。

          二.STM32使用DMA

          1.DMA的設(shè)置:

          要配置的有DMA傳輸通道選擇,傳輸?shù)某蓡T和方向、普通模式還是循環(huán)模式等等。

          void DMA_Configuration(void)
          {
          DMA_InitTypeDef DMA_InitStructure;
          //DMA設(shè)置:
          //設(shè)置DMA源:內(nèi)存地址&串口數(shù)據(jù)寄存器地址
          //方向:內(nèi)存-->外設(shè)
          //每次傳輸位:8bit
          //傳輸大小DMA_BufferSize=SENDBUFF_SIZE
          //地址自增模式:外設(shè)地址不增,內(nèi)存地址自增1
          //DMA模式:一次傳輸,非循環(huán)
          //優(yōu)先級(jí):中
          DMA_DeInit(DMA1_Channel4);//串口1的DMA傳輸通道是通道4
          DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
          DMA_InitStructure.DMA_MemoryBaseAddr =(u32)SendBuff;//DMA訪問(wèn)的數(shù)據(jù)地址
          DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralDST;//外設(shè)作為DMA的目的端
          DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//傳輸數(shù)據(jù)大小
          DMA_InitStructure.DMA_PeripheralInc =DMA_PeripheralInc_Disable;//外設(shè)地址不增加
          DMA_InitStructure.DMA_MemoryInc =DMA_MemoryInc_Enable;//內(nèi)存地址自增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 (循環(huán)傳送)
          DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA傳送優(yōu)先級(jí)為中等)
          DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
          DMA_Init(DMA1_Channel4, &DMA_InitStructure);
          }
          注:
          1、傳輸通道:通過(guò)查表,串口1的發(fā)送對(duì)應(yīng)的是DMA的通道4,所以此處選擇通道4.
          2、DMA傳輸方式:
          (1) DMA_Mode_Normal,正常模式,當(dāng)一次DMA數(shù)據(jù)傳輸完后,停止DMA傳送,對(duì)于上例而言,就是DMA_PeripheralDataSize_Byte個(gè)字節(jié)的傳送完成后,就停止傳送。
          (2)DMA_Mode_Circular
          循環(huán)模式,當(dāng)傳輸完一次后,重新接著傳送,永不停息。
          2、外設(shè)的DMA方式設(shè)置
          將串口1設(shè)置成DMA模式:
          USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
          3、待傳輸數(shù)據(jù)的定義和初始化
          #define SENDBUFF_SIZE10240
          vu8 SendBuff[SENDBUFF_SIZE];
          for(i=0;i{
          SendBuff[i] = i+0;
          }
          4、開始DMA傳輸(使能對(duì)應(yīng)的DMA通道)
          DMA_Cmd(DMA1_Channel4, ENABLE);
          5、DMA傳輸?shù)耐瓿?/div>
          while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
          {
          LED_1_REV;//LED改變亮滅
          Delay();//浪費(fèi)時(shí)間
          }
          當(dāng)傳輸完成后,就會(huì)跳出上面的死循環(huán)。
          下面是九九的一個(gè)例程,測(cè)試過(guò),可以運(yùn)行!

          #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");
          //發(fā)送去數(shù)據(jù)已經(jīng)準(zhǔn)備好,按下按鍵即開始傳輸
          while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));

          printf("Start DMA transmission!rn");

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

          //等待DMA傳輸完成,此時(shí)我們來(lái)做另外一些事,點(diǎn)燈
          //實(shí)際應(yīng)用中,傳輸數(shù)據(jù)期間,可以執(zhí)行另外的任務(wù)
          while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
          {
          Delay();//浪費(fèi)時(shí)間
          }
          //DMA傳輸結(jié)束后,自動(dòng)關(guān)閉了DMA通道,而無(wú)需手動(dòng)關(guān)閉
          //下面的語(yǔ)句被注釋
          //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);
          //等待外部晶振穩(wěn)定
          HSEStartUpStatus = RCC_WaitForHSEStartUp();
          //如果外部晶振啟動(dòng)成功,則進(jìn)行下一步操作
          if(HSEStartUpStatus==SUCCESS)
          {
          //設(shè)置HCLK(AHB時(shí)鐘)=SYSCLK
          RCC_HCLKConfig(RCC_SYSCLK_Div1);
          //PCLK1(APB1) = HCLK/2
          RCC_PCLK1Config(RCC_HCLK_Div2);
          //PCLK2(APB2) = HCLK
          RCC_PCLK2Config(RCC_HCLK_Div1);
          //FLASH時(shí)序控制
          //推薦值:SYSCLK = 0~24MHzLatency=0
          //SYSCLK = 24~48MHzLatency=1
          //SYSCLK = 48~72MHzLatency=2
          FLASH_SetLatency(FLASH_Latency_2);
          //開啟FLASH預(yù)取指功能
          FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
          //PLL設(shè)置 SYSCLK/1 * 9 = 8*1*9 = 72MHz
          RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
          //啟動(dòng)PLL
          RCC_PLLCmd(ENABLE);
          //等待PLL穩(wěn)定
          while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
          //系統(tǒng)時(shí)鐘SYSCLK來(lái)自PLL輸出
          RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
          //切換時(shí)鐘后等待系統(tǒng)時(shí)鐘穩(wěn)定
          while(RCC_GetSYSCLKSource()!=0x08);


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

          }

          void GPIO_Configuration(void)
          {
          GPIO_InitTypeDef GPIO_InitStructure;
          //PC口4567腳設(shè)置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腳,使能設(shè)置為輸入
          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
          //設(shè)置NVIC優(yōu)先級(jí)分組為Group2:0-3搶占式優(yōu)先級(jí),0-3的響應(yīng)式優(yōu)先級(jí)
          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設(shè)置:
          //設(shè)置DMA源:內(nèi)存地址&串口數(shù)據(jù)寄存器地址
          //方向:內(nèi)存-->外設(shè)
          //每次傳輸位:8bit
          //傳輸大小DMA_BufferSize=SENDBUFF_SIZE
          //地址自增模式:外設(shè)地址不增,內(nèi)存地址自增1
          //DMA模式:一次傳輸,非循環(huán)
          //優(yōu)先級(jí):中
          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;//外設(shè)作為DMA的目的端
          DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//傳輸大小
          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外設(shè)地址不增加
          DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//內(nèi)存地址自增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傳送優(yōu)先級(jí)為中等)
          DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
          DMA_Init(DMA1_Channel4, &DMA_InitStructure);
          }



          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();