STM32 DAM之串口通訊


 

    本代碼基於STM32F030F4P6,程序運行后完成以下功能:

1.  定義了串口的發送和接收數組各20字節,賦值發送數組默認字符串“Hellow Good morning!”。

2.  用TIM16做了5秒的定時器,定時結束后進TIM16中斷,中斷內改變主環條件變量,啟動DMA

     控制串口發送字符串Hellow Good morning!。

3.  DMA控制串口發送結束后,進入DMA中斷,在中斷中重啟TIM16的5秒的定時器。

4.  重復上面步驟2、3,實現每5秒發送字符串Hellow Good morning!,通過串口軟件的接收窗口

     觀察,另外每發送一次,指示燈亮滅變化一次。

5.  可以在串口軟件的發送窗口發送20字節的字符串,DMA控制串口接收結束后,進入DMA中

     斷,中斷內改變主環條件變量,將接收的20字節的字符串賦值給發送數組。這樣當新的5秒

    定時到來時,發送的將是剛才從串口接收的新字符串,可以通過串口軟件的接收窗口看到每

    隔5秒回有字符串收到。

6.  注意串口軟件波特率等的設置要和程序一致,STM32F030系列的DMA不支持外設到外設,

     STM32F030只有DMA1,沒有DMA2,注意不同外設對應不同DMA通道,而且不同芯片的通

     道也不一定相同,還有IO配置、復用功能選擇等都要仔細看數據手冊。

     中斷程序加入代碼如下:

 #include "stm32f0xx_it.h" //轉載請注明出處: https://www.cnblogs.com/beiyhs/p/12058056.html  北有寒山

#include "stm32f0xx_tim.h"

extern _Bool ur_txflg ; //定義發送標志位變量; 聲明外部變量
extern _Bool ur_rxflg ; //定義發送標志位變量; 聲明外部變量

//*****************************************************************************

void DMA1_Channel2_3_IRQHandler(void)
{
  if(DMA_GetITStatus(DMA1_IT_TC2) != RESET)     // 判斷DMA發送完成中斷
               {
                TIM_Cmd(TIM16, ENABLE);                      //使能TIM16 重新計時
                DMA_ClearITPendingBit(DMA1_IT_TC2); //清除DMA中斷標志位
                }

 if(DMA_GetITStatus(DMA1_IT_TC3) != RESET)    // 判斷DMA接收完成中斷
                {
                 DMA_ClearITPendingBit(DMA1_IT_TC3); //清除DMA中斷標志位
                 ur_rxflg=1;
                 }
 }

//*****************************************************************************

void TIM16_IRQHandler(void)                                    //TIM16定時中斷
{
TIM_ClearITPendingBit(TIM16,TIM_IT_Update);       //清TIM16溢出中斷標志位
TIM_Cmd(TIM16,DISABLE);                                      //失能TIM16
ur_txflg=1;                                                                   //設置發送標志位
}
//****************************************************************************************

//****************************************************************************************

 主程序代碼如下:

#include "stm32f0xx.h"
#include "stm32f0xx_rcc.h"
#include "stm32f0xx_gpio.h"
#include "stm32f0xx_dma.h"
#include "stm32f0xx_usart.h"

#define USART1_TDR_Address ((uint32_t)(USART1_BASE+0x28)) //宏定義串口發送寄存器地址
#define USART1_RDR_Address ((uint32_t)(USART1_BASE+0x24)) //宏定義串口接收寄存器地址

unsigned char TxStr[20]={"Hellow Good morning!"};           //定義發送緩存數組的字符
unsigned char RxStr[20];                                                      //定義接受緩存數組變量

_Bool ur_txflg=0;                                                                  //定義發送標志位變量
_Bool ur_rxflg=0;                                                                  //定義發送標志位變量

void USART_cfg(void);                                                        //串口IO配置函數
void GPIO_cfg(void);                                                           //發送IO的配置函數
void TIM16_INIT_Config(void);                                           //TIM16中斷初始化函數

void DMA1_txcfg(void);                                                       //DMA的配置函數
void DMA1_NVIC_Init(void);                                               //DMA中斷配置函數

void LED_Init(void);                                                             //閃燈初始化函數

 //***********************************************************************************************************

void GPIO_cfg(void) //發送IO的配置函數
{
 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //打開A口時鍾

 GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);  //設置發送PA9的AF復用或PA2
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource10,GPIO_AF_1); //設置接受PA10的AF復用或PA3
 //發送配置
 GPIO_InitTypeDef UART1_TX;                          //聲明UART1_TX是GPIO_InitTypeDef結構變量
 UART1_TX.GPIO_Pin = GPIO_Pin_9;                      //設PA9為TX
 UART1_TX.GPIO_Speed = GPIO_Speed_10MHz;  //設定端口最快輸出10MHz
 UART1_TX.GPIO_Mode = GPIO_Mode_AF;           //設置IO復用模式
 UART1_TX.GPIO_OType=GPIO_OType_PP;          // 推挽輸出
 UART1_TX.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(GPIOA, &UART1_TX);                            //按以上參數初始化GPIOA_9
 //接收配置
 GPIO_InitTypeDef UART1_RX;                          //聲明UART1_TX是GPIO_InitTypeDef結構變量
 UART1_RX.GPIO_Pin = GPIO_Pin_10;                   //設PA10為RX
 UART1_RX.GPIO_Speed = GPIO_Speed_10MHz; //設定端口最快輸出10MHz
 UART1_RX.GPIO_Mode = GPIO_Mode_AF;          //設置IO復用模式
 UART1_RX.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(GPIOA, &UART1_RX);                           //按以上參數初始化GPIOA_10
}

//*********************************************************************************************************

 void USART1_cfg(void)                                                                                 //發送IO的配置函數

{
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);       //打開串口時鍾
 USART_InitTypeDef USART_InitStructure;
 USART_InitStructure.USART_BaudRate = 115200;                                    //設置波特率
 USART_InitStructure.USART_WordLength = USART_WordLength_8b;    //設置數據長度
 USART_InitStructure.USART_Parity = USART_Parity_No;                        //設置奇偶校驗
 USART_InitStructure.USART_StopBits = USART_StopBits_1;                  //設置停止位
 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //設置流控制
 USART_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx; //設置為收發模式
 USART_Init(USART1, &USART_InitStructure);
//USART_ClearFlag(USART1,USART_FLAG_TC);
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);                     //串口1發射DMA使能
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);                    //串口1接收DMA使能
USART_Cmd(USART1, ENABLE);                                                               //串口1使能
}
//************************************************************************************************

 void DMA1_txcfg(void)                                                                                 //DMA Tx設置

{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);    //1 使能DMA傳輸,開啟DMA時鍾
DMA_InitTypeDef DMA_InitStructu;                                                  //2 聲明DMA結構變量
DMA_DeInit(DMA1_Channel2);                                            //3 復位,stm32f0xx.h定義TX使用DMA1通道2
DMA_InitStructu.DMA_PeripheralBaseAddr = USART1_TDR_Address; //4 DMA外設TX基地址 目標地址
DMA_InitStructu.DMA_MemoryBaseAddr =(uint32_t)TxStr;          //5 DMA內存基地址/數據首地址 源地址
DMA_InitStructu.DMA_DIR = DMA_DIR_PeripheralDST;              //6 內存作為數據傳輸的源,內存發到外設
DMA_InitStructu.DMA_BufferSize =20;                            //7 DMA通道的DMA緩存的大小20,發送數據長度
DMA_InitStructu.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //8 TX寄存器地址不變,目標地址不變
DMA_InitStructu.DMA_MemoryInc = DMA_MemoryInc_Enable; //9 內存地址寄存器地址遞增,源地址加1
DMA_InitStructu.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//10 數據寬度為8位
DMA_InitStructu.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte; //11 串口發送 寬度為8位

DMA_InitStructu.DMA_Mode = DMA_Mode_Normal; //12 工作在正常緩存模式/Circular循環模式
DMA_InitStructu.DMA_Priority = DMA_Priority_High; //13 DMA通道 擁有高優先級/Medium 中優先
DMA_InitStructu.DMA_M2M = DMA_M2M_Disable; //14 DMA通道 關閉內存到內存傳輸
DMA_Init(DMA1_Channel2, &DMA_InitStructu); //15 據DMA_InitStruct中指定的參數初始化DMA1的通道2
//DMA_Cmd(DMA1_Channel2,ENABLE); //16 啟動DMA通道,意味發送開始,放在主環
//DMA_ClearITPendingBit(DMA1_IT_TC2); // 清除一次DMA中斷標志 
DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE); // 使能DMA 傳輸完成 的中斷
}
//**********************************************************************************************************************

 

void DMA1_rxcfg(void) // DMA Rx設置
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //1 使能DMA傳輸,開啟DMA時鍾
DMA_InitTypeDef DMA_InitStructu; //2 聲明DMA結構變量
// DMA_Cmd(DMA1_Channel3,DISABLE);
DMA_DeInit(DMA1_Channel3); //3 復位,stm32f0xx.h定義RX使用DMA1通道3
DMA_InitStructu.DMA_PeripheralBaseAddr =USART1_RDR_Address; //4 DMA外設RX基地址 源地址
DMA_InitStructu.DMA_MemoryBaseAddr = (uint32_t)&RxStr; //5 DMA內存基地址/數據首地址 目標
DMA_InitStructu.DMA_DIR = DMA_DIR_PeripheralSRC; //6 串口為數據傳輸的源,外設發到內存
DMA_InitStructu.DMA_BufferSize = 20; //7 DMA通道的DMA緩存的大小20,發送數據長度
DMA_InitStructu.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //8 RX寄存器地址不變,目標地址不變
DMA_InitStructu.DMA_MemoryInc = DMA_MemoryInc_Enable; //9 內存地址寄存器地址遞增,目標地址加1
DMA_InitStructu.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//10 數據寬度為8位
DMA_InitStructu.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //11 串口發送的數據寬度為8位
DMA_InitStructu.DMA_Mode = DMA_Mode_Normal;//Circular; //12 工作在循環緩存模式/Normal
DMA_InitStructu.DMA_Priority = DMA_Priority_High; //13 DMA通道 擁有高優先級/Medium 中優先
DMA_InitStructu.DMA_M2M = DMA_M2M_Disable; //14 DMA通道 關閉內存到內存傳輸
DMA_Init(DMA1_Channel3,&DMA_InitStructu); //15 據DMA_InitStruct中指定的參數初始化DMA1的通道3
DMA_Cmd(DMA1_Channel3,ENABLE); //16 啟動DMA通道
// USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //串口1發射DMA使能,放在USART函數最好
}

//***************************************************************************************************************************

 void DMA1_NVIC_Init(void)                                                                  //DMA中斷配置函數

{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_3_IRQn; //設定DMA1通道2、3中斷請求
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                     //使能中斷請求
NVIC_InitStructure.NVIC_IRQChannelPriority = 2;                            //中斷優先級2
NVIC_Init(&NVIC_InitStructure);
}

//**************************************************************************************************************************

void TIM16_INIT_Config(void)                                                //TIM16中斷初始化函數
{ //TIM中斷間隔5s
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;            //聲明TIM_TimeBaseInitTypeDef結構變量
NVIC_InitTypeDef NVIC_InitStructure;                                   //聲明NVIC_InitTypeDef 向量結構變量
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM16, ENABLE); //使能TIM16時鍾

// 定時器基礎設置
TIM_TimeBaseStructure.TIM_Period = 47999;                     //設置自動重載計數=47999+1=48000
TIM_TimeBaseStructure.TIM_Prescaler =4999;                   //定時器預分頻=TIM_Prescaler+1=5000;
                                                                                              //頻率=48M/5000/48000=0.2,時間=1/0.2=5s
TIM_TimeBaseStructure.TIM_ClockDivision = 1;                 //輸入捕獲時濾波用的參數,必須設一下
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;          //重復計數設置
TIM_TimeBaseInit(TIM16, &TIM_TimeBaseStructure);        //根據指定的參數初始

// TIM16中斷嵌套設置
NVIC_InitStructure.NVIC_IRQChannel = TIM16_IRQn;      //選擇TIM16的IRQ通道
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;             //IRQ通道優先級=0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;     //使能IRQ通道
NVIC_Init(&NVIC_InitStructure);                                          //按以參數上設置

TIM_ARRPreloadConfig(TIM16, DISABLE);                       //禁止ARR預裝載緩沖,就是不改變TIM_Period
TIM_ClearFlag(TIM16, TIM_FLAG_Update);                      //清除狀態標志位

TIM_ClearITPendingBit(TIM16,TIM_IT_Update);                //1 清TIM16溢出中斷標志位
TIM_ITConfig(TIM16,TIM_IT_Update, ENABLE);               //2 使能TIM16溢出中斷
TIM_Cmd(TIM16, DISABLE);                                              //3 使能TIM16中斷 1/2/3順序莫錯
}
//********************************************************************************************************
void LED_Init(void) //LED初始化函數
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);   //使能A口的時鍾
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;                                        //指明A4口
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;                           //設定輸出模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;                          //設定輸出為上拉
GPIO_InitStruct.GPIO_Speed =GPIO_Speed_Level_3;                   //設定級別為3
GPIO_Init(GPIOA, &GPIO_InitStruct);                                               //按以上設置初始化A4
}

//********************************************************************************************************

void LED_A4(void) //亮燈取反滅燈函數
{
GPIO_WriteBit(GPIOA, GPIO_Pin_4,                                                //指定修改A4腳的位
(BitAction)((1-GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_4))));  //讀A4狀態后取反
}

//**********************************************************************************************
//**********************************************************************************************
int main(void)
{
GPIO_cfg();                             //串口發送管腳初始化
USART1_cfg();                        //串口初始化
DMA1_txcfg();                         //DMA1_tx初始化
DMA1_rxcfg();                         //DMA1_rx初始化
DMA1_NVIC_Init();                 //DMA中斷初始化
TIM16_INIT_Config();             //定時器中斷初始化
TIM_Cmd(TIM16, ENABLE);  //使能TIM16 中斷
LED_Init() ;                             //閃燈初始化函數

while(1)                                   //主循環
  {
  if(ur_txflg==1)                                                                      //判斷發送標志位變量
            {
             ur_txflg=0;                                                                //發送標志位變量重置0
             LED_A4();                                                                //閃燈函數,每次發送燈狀態變化一次

             DMA_Cmd(DMA1_Channel2,DISABLE);                // 發送完成先關掉DMA通道
             DMA_SetCurrDataCounter(DMA1_Channel2,20);  // 每次DMA傳完會變0,要先關通道再重設長度
             DMA_Cmd(DMA1_Channel2,ENABLE);                 // 再打開DMA通道,意味着開始傳輸
              }
  if(ur_rxflg==1)                                                                     //判斷接收標志位變量
            {
             ur_rxflg=0; //接收標志位變量重置0
             for (char i=0; i<20; ++i)
                  {
                   TxStr[i] = RxStr[i];
                   DMA_Cmd(DMA1_Channel3,DISABLE);               // 接收完成先關掉DMA通道
                   DMA_SetCurrDataCounter(DMA1_Channel3,20); // 每次DMA傳完會變0,要先關通道再重設長度
                   DMA_Cmd(DMA1_Channel3,ENABLE);                // 再打開DMA通道,意味着開始傳輸
                   }
             }

   }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM