STM32F10X USART 中断接受+发送,测试无误

来源:互联网 发布:2016淘宝怎么刷 编辑:程序博客网 时间:2024/06/09 16:50

硬件平台:STM32F10X  USART模块 + JLink+USB转TTL小板

软件平台:Keil 4 

前一个程序只是作为下位机的MCU将数据发送给串口助手,也就是上位机,相当于单工通信,对于一个完整的通信来说只是完成了一半的功能。

这是一个完整的通信例程,作为下位机的单片机可以将数据发送给上位机,也可以检测上位机是否发了数据回来。中断方式检测,如果接收到数据,则将数据发送给上位机,相当于半双工模式。

其实与基础的51串口通信无实质区别,只是STM32相关寄存器配置稍微复杂些而已。相比于前一个发送程序,只是在中断检测和主函数里做了相应的修改而已,RCC模块、USART模块与GPIO模块配置基本没变。

二、发送程序例程

程序涉及的模块有:

RCC:复位及时钟控制模块,用于初始化STM32 USART外设时钟及IO口复用时钟;

USART:通用同步异步收发器,即串口,用于发送数据至上位机显示已发送的数据;

GPIO:通用输入输出口复用配置模块。

1、RCC(复位和时钟控制 RESET CLOCK Controller)配置:常规时钟配置+USART相对应的IO口时钟+USART时钟              + 管脚功能复用时钟

  2、GPIO(通用输出输入口)配置 AFIO 复用...:发送端推挽输出,接收端浮空输入

3、USART配置:通用同步异步收发器:8bits一帧,通过缓存区交换

4、NVIC配置(Nest Vector Interrupt Controller):嵌入中断向量控制器

中断响应

中断优先级:优先级编号小者优先级高

查询优先级+执行优先级

多个中断挂起时,执行优先级高者先执行

若执行优先级同,先执行查询优先级高的,在中断向量表的位置决定

中断嵌套:优先级低着被打断,CPU先执行优先级高者

中断挂起:执行高的时候,低者来了,低者被挂起,等待执行

NVIC 管理中断优先级,256个中断分配优先级,次占优先级不会造成中断嵌套

5、发送接收数据

RCC

  //RCC时钟配置  void RCC_cfg(void)  {    ErrorStatus HSEStartUpStatus;  //定义错误状态变量      RCC_DeInit();////将RcC初始化,重新设置为默认值     RCC_HSEConfig(RCC_HSE_ON);   //打开外部高速时钟晶振,使能HSE  /*RCC_HSE_ON  开   _off 关  _bypass hse晶振被外部时钟旁路*/     HSEStartUpStatus = RCC_WaitForHSEStartUp();  /*RCC_WaitForHSEStartUp()返回一个ErrorStatus枚举值,  success好,error未好*/     if(HSEStartUpStatus == SUCCESS)//HES就绪   {    RCC_HCLKConfig(RCC_SYSCLK_Div1);   //AHB时钟(HCLK)=系统时钟    RCC_PCLK1Config(RCC_HCLK_Div2);   //设置低速AHB时钟(APB1)为HCLK的2分频       RCC_PCLK2Config(RCC_HCLK_Div1);   //设置高速AHB时钟(APB2)=HCLK时钟       FLASH_SetLatency(FLASH_Latency_2);   //设置FLASH代码延时      //使能领取指缓存   FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);      RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);   //设置PLL时钟源及倍频系数,为HSE的9倍频 8MHz * 9 = 72MHz   /*void RCC_PLLConfig(u32 RCC_PLLSource, u32 RCC_PLLMul)   RCC_PLLSource_HSI_Div2   pll输入时钟=hsi/2;   RCC_PLLSource_HSE_Div1   pll输入时钟 =hse   RCC_PLLSource_HSE_Div2   pll输入时钟=hse/2      RCC_PLLMul_2  ------_16       pll输入时钟*2---16   pll输出时钟不得超过72MHZ*/       RCC_PLLCmd(ENABLE);   //ENABLE  / DISABLE      while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);//等待就绪   /*FlagStatus RCC_GetFlagStatus(u8 RCC_FLAG)  检查指定RCC标志位   返回SET OR RESET   RCC_FLAG_HSIRDY  HSI晶振就绪   RCC_FLAG_HSERDY   RCC_FLAG_PLLRDY   RCC_FLAG_LSERDY    RCC_FLAG_LSIRDY.......*/       RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);   //设置PLL为系统时钟源   /*void RCC_SYSCLKConfig(u32 RCC_SYSCLKSource)  设置系统时钟   RCC_SYSCLKSource_HSI    RCC_SYSCLKSource_HSE    RCC_SYSCLKSource_PLLCLK  选HSI  HSE PLL 作为系统时钟*/        while(RCC_GetSYSCLKSource() != 0x08);   //判断PLL是否是系统时钟   /*u8 RCC_GetSYSCLKSource(void)  返回用作系统时钟的时钟源   0x00:HSI   0x04:HSE 0x08:PLL */   }    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO , ENABLE);   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);   //打开GPIO时钟,复用功能,串口1的时钟   /*void RCC_APB2PeriphClockCmd(u32 RCC_APB2Periph, FunctionalState NewState)   enable 或 disable apb2 外设时钟   RCC_APB2Periph_AFIO  功能复用IO 时钟   RCC_APB2Periph_GPIOA/B/C/D/E   GPIOA/B/C/D/E 时钟   RCC_APB2Periph_ADC1/ADC2ADC1/2 时钟   RCC_APB2Periph_TIM1    RCC_APB2Periph_SPI1   RCC_APB2Periph_USART1    RCC_APB2Periph_ALL全部APB2外设时钟*/  }

GPIO

  //IO口配置  void GPIO_cfg(void)  {   GPIO_InitTypeDef GPIO_InitStructure;  //GPIO_InitStructure初始化结构体为GPIO_InitTypeDef结构     //PA9作为US1的TX端,打开复用,负责发送数据     GPIO_StructInit(&GPIO_InitStructure);  /*typedef struct   {   u16 GPIO_Pin;   GPIOSpeed_TypeDef GPIO_Speed;   GPIOMode_TypeDef GPIO_Mode;   } GPIO_InitTypeDef;*/  //函数:指向结构GPIO_InitTypeDef的指针,待初始化  //GPIO_StructInit中的成员:GPIO_PIN/SPEED/MODE     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;  //1、选中引脚GPIO_PIN_0--15 OR GPIO_PIN_ALL 选中全部管脚    //2、GPIO_SPEED:GPIO_SPEED_10MHz/_2MHz/_50MHz   最高输出速率   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  /*Mode,工作状态:GPIO_MODE_AIN  ----- 模拟输入  _IN_FLOATING  ----- 浮空输入  _IPD  ----- 上拉输出  _IPU  ----- 上拉输入  _OUT_OD  ----- 开漏输出  _OUT_PP  ----- 推挽输出  _AF_OD  ----- 复用开漏输出  _AF_PP  ----- 复用推挽输出*/     GPIO_Init(GPIOB , &GPIO_InitStructure);   //选择A,初始化     //PA10作为US1的RX端,负责接收数据   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;   //选择10脚      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   //IO浮空输入   GPIO_Init(GPIOB, &GPIO_InitStructure);   //初始化      //提示标示:LED显示串口正在发送数据/接收数据   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //推挽输出   GPIO_Init(GPIOA, &GPIO_InitStructure);  }

USART

  //串口初始化  void USART_cfg(void)  {   USART_InitTypeDef USART_InitStructure;      USART_StructInit(&USART_InitStructure);  //将结构体设置为缺省状态  /*USART_StructInit通用同步异步串行口初始结构成员:  USART_BaudRate----9600,默认9600  IntegerDivider = ((APBClock) / (16 *  (USART_InitStruct->USART_BaudRate)))   FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 16) + 0.5     _WordLength  帧中传输的数据位----USART_WordLength_8b/_9b,字长宽8位   _StopBits  停止位  可为 USART_StopBits_1 ---帧结尾传输1个停止位  USART_StopBits_0.5  0.5个  USART_StopBits_2  USART_StopBits_1.5   _parity  奇偶模式  USART_Parity_No//奇偶失能,无奇偶  USART_Parity_even oumoshi  USART_Parity_odd  jimoshi         奇偶使能时,在数据的MSB位插入奇偶位,字长9位时的第九位,8位时的第八位   _HardwareFlowControl  //  _none,硬件流控制失能  _rts 发送请求rts使能  _cts 清除发送cts使能  _rts_cts rts and cts 使能*/     //波特率设置为115200   USART_InitStructure.USART_BaudRate = 115200;   //一帧数据的宽度设置为8bits   USART_InitStructure.USART_WordLength = USART_WordLength_8b;   //在帧尾传输1个停止位   USART_InitStructure.USART_StopBits = USART_StopBits_1;   //奇偶检验失能模式,无奇偶校验位   USART_InitStructure.USART_Parity = USART_Parity_No;   //发送/接收使能   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   //硬件流控制失能   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;   //设置串口3   USART_Init(USART3, &USART_InitStructure);     //打开串口3的中断响应函数      USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);   /*void USART_ITConfig(USART_TypeDef* USARTx, u16 USART_IT, FunctionalState NewState)   失能或使能相应的USART中断,x---1/2/3  _IT : _IT_PE  奇偶错误中断  _IT_TXE FASONG中断  _IT_TC  传输完成中断  _IT_RXNE  接收中断  _IT_IDLE  空闲总线中断  _IT_LBD  LIN中断检测中断  _IT_CTS  CTS中断  _IT_ERR  错误中断*/     USART_Cmd(USART3, ENABLE);   /*void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)   失能或使能外设 x--1/2/3   NewState: USARTx ENABLE /DISABLE*/  }
NVIC

  //配置中断  void NVIC_cfg(void)  {   NVIC_InitTypeDef NVIC_InitStructure;  //定义NVIC初始化结构体 NVIC_InitStructure     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  /*优先级分组:先占优先级与从优先级,只可设置一次  NVIC_PriorityGroup_0  先0位从4位 0  0--15  NVIC_IRQChannelPreemptionPriority 对中断通道设置不产生影响  NVIC_PriorityGroup_1先1位从3位0-1 0--7  NVIC_IRQChannelSubPriority 不影响中断  NVIC_PriorityGroup_2先2从20-3  0-3  NVIC_PriorityGroup_3先3从10-7 0-1  NVIC_PriorityGroup_4先4从00-15  0  选择中断优先级分组2*/      NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;   //UA=SART1 全局中断  //用3.5的库的时候,所有的USART1_IRQChannel全部换成USART1_IRQn;!!!!!  /*typedef struct   {   u8 NVIC_IRQChannel; //enable/disable 相应的IRQ通道,3.5库的时候,IRQChannel全部换成IRQn  u8 NVIC_IRQChannelPreemptionPriority;//成员 NVIC_IRQChannel先占优先级  u8 NVIC_IRQChannelSubPriority; //成员 NVIC_IRQChannel从占优先级  FunctionalState NVIC_IRQChannelCmd; //成员 NVIC_IRQChannel 使能还是失能  } NVIC_InitTypeDef;*/    //选择串口1中断   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //抢占式,先占   中断优先级设置为0   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //响应式,从  中断优先级设置为0   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  //使能中断   NVIC_Init(&NVIC_InitStructure);  }    #include "stm32f10x_it.h"    extern FlagStatus RX_status;  extern char urt_flag;  void USART3_IRQHandler(void)  {   GPIO_SetBits(GPIOA, GPIO_Pin_4);     RX_status = USART_GetFlagStatus(USART3, USART_FLAG_RXNE);   //确认是否收到数据      //USART_ClearFlag(USART3,USART_FLAG_TC);//清除usart1-3 待处理标志位        if(USART_GetITStatus(USART3,USART_IT_RXNE)==SET)  //中断发生与否,接收中断  {   USART_ClearITPendingBit(USART3,USART_IT_RXNE);  //清除usart1-3的中断待处理位   urt_flag=1;  }    if(USART_GetFlagStatus(USART3,USART_FLAG_ORE)==SET)  //溢出,若溢出,先读取SR,再读取 DR ,寄存器可清除不断入中断的问题  {   USART_ClearFlag(USART3,USART_FLAG_ORE);   //读取SR ,清除溢出错误标志位  USART_ReceiveData(USART3);//读取DR     /*USART_SendData(USART3, USART_ReceiveData(USART3));  //将数据发送到上位机  while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);  //等待数据发送完毕  //USART3_Puts("\r\n");  GPIO_ResetBits(GPIOA, GPIO_Pin_4);  //发送完后亮灯*/  urt_flag=1;  }     }

欢迎讨论,共同学习



0 0