zoukankan      html  css  js  c++  java
  • 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通道,意味着开始传输
                       }
                 }

       }
    }

  • 相关阅读:
    linux g++编译dxf文件C++解析库dxflib
    linux g++使用总结
    一个使用three.js的网页DXF文件查看器dxf viewer
    node.js教程基础:node.js访问操作系统
    node.js教程基础:node.js全局对象
    node.js教程基础:node.js命令行选项
    node.js教程基础:node.js包管理器
    node.js教程基础:node.js REPL
    node.js教程基础:第一个node.js程序
    node.js教程基础:node.js安装
  • 原文地址:https://www.cnblogs.com/beiyhs/p/12058056.html
Copyright © 2011-2022 走看看