STM32
直播中

王兰

14年用户 943经验值
擅长:基础元器件
私信 关注
[问答]

串口配置的一般步骤有哪些

串口配置的一般步骤有哪些?
常用IO口的模式有哪几种?

回帖(1)

张燕

2021-9-29 17:29:44
  
  寄存器映射
  
  
  
  
  
  
  
  新建工程
  
  
  仿照51添加启动文件和main.c编译报错。
  
  
  main.c中:
  
  
  
  置位和复位不要直接赋值0或者1,否则有可能覆写别的位
  
  正点原子
  下载,ch340G
  
  LED
  整合了德飞莱 C8T6最小系统板 ZET6最小系统板 LED灯的代码
  
  led.h
  #ifndef __LED_H
  #define __LED_H
  #include “sys.h”
  //
  #define LED1 PBout(5)// PB5
  #define LED2 PEout(5)// PE5
  #define LED12 PBout(12)
  #define LED8 PFout(8)// PB5
  #define LED9 PFout(9)// PE5
  #define LED_ON 0
  #define LED_OFF 1
  void LED_Init(void);//初始化
  void bsp_LedOn(uint8_t _no); // 点亮指定的LED指示灯
  void bsp_LedOff(uint8_t _no); // 熄灭指定的LED指示灯
  void bsp_LedToggle(uint8_t _no); // 翻转指定的LED指示灯
  #endif
  led,c
  #include “led.h”
  //
  //初始化PB5和PE5为输出口。并使能这两个口的时钟
  //LED IO初始化
  void LED_Init(void)
  {
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口时钟
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0--》PB.5 端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
  GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1--》PE.5 端口配置, 推挽输出
  GPIO_Init(GPIOE, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //LED1--》PE.5 端口配置, 推挽输出
  GPIO_Init(GPIOB, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; //LED1--》PE.5 端口配置, 推挽输出
  GPIO_Init(GPIOF, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
  GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
  GPIO_SetBits(GPIOE,GPIO_Pin_5); //PE.5 输出高
  }
  /*
  *********************************************************************************************************
  * bsp_LedOn()
  * Description : 点亮指定的LED指示灯
  * Arguments : _no:The ID of the LED to control
  * 0:点亮所有LED
  * 1:点亮1号LED
  * 2:点亮2号LED
  * 3:点亮3号LED
  * :
  * Returns : NO
  * Note(s) :
  *********************************************************************************************************
  */
  void bsp_LedOn(uint8_t _no)
  {
  switch (_no)
  {
  case 0:
  LED1=LED_ON;
  LED2=LED_ON;
  LED12=LED_ON;
  LED8=LED_ON;
  LED9=LED_ON;
  break;
  case 1:
  LED1=LED_ON;
  break;
  case 2:
  LED2=LED_ON;
  break;
  case 12:
  LED12=LED_ON;
  break;
  case 8:
  LED8=LED_ON;
  break;
  case 9:
  LED9=LED_ON;
  break;
  default:
  break;
  }
  }
  /*
  *********************************************************************************************************
  * bsp_LedOff()
  * Description : 熄灭指定的LED指示灯
  * Arguments : _no:The ID of the LED to control
  * 0:关闭所有LED
  * 1:关闭1号LED
  * 2:关闭2号LED
  * 3:关闭3号LED
  * :
  * Returns : NO
  * Note(s) :
  *********************************************************************************************************
  */
  void bsp_LedOff(uint8_t _no)
  {
  switch (_no)
  {
  case 0:
  LED1=LED_OFF;
  LED2=LED_OFF;
  LED12=LED_OFF;
  LED8=LED_OFF;
  LED9=LED_OFF;
  break;
  case 1:
  LED1=LED_OFF;
  break;
  case 2:
  LED2=LED_OFF;
  break;
  case 12:
  LED12=LED_OFF;
  break;
  case 8:
  LED8=LED_OFF;
  break;
  case 9:
  LED9=LED_OFF;
  break;
  default:
  break;
  }
  }
  /*
  *********************************************************************************************************
  * bsp_LedToggle()
  * Description : 翻转指定的LED指示灯
  * Arguments : _no:The ID of the LED to control
  * 0:切换所有LED
  * 1:切换1号LED
  * 2:切换2号LED
  * 3:切换3号LED
  * :
  * Returns : NO
  * Note(s) :
  *********************************************************************************************************
  */
  void bsp_LedToggle(uint8_t _no)
  {
  switch (_no)
  {
  case 0:
  LED1=!LED1;
  LED2=!LED2;
  LED8=!LED8;
  LED9=!LED9;
  LED12=!LED12;
  break;
  case 1:
  LED1=!LED1;
  break;
  case 2:
  LED2=!LED2;
  break;
  case 12:
  LED12=!LED12;
  break;
  case 8:
  LED8=!LED8;
  break;
  case 9:
  LED9=!LED9;
  break;
  }
  }
  main.c
  {LED1=!LED1;LED12=!LED12;LED8=!LED8;}//闪烁LED,提示系统正在运行。
  正点原子工程文件结构:
  
  GPIO
  
  很多小伙伴们在初学stm32时都对stm32的IO口工作模式的原理和配置不了解,所以我整理发表此篇文章作为自己复习和他人参考资料。(注:该文章参考了stm32官方数据手册和正点原子教学资料)
  在Cortex-M3里对于GPIO的配置种类有8种之多,4种输入模式,4种输出模式:
  (1)GPIO_Mode_AIN 模拟输入
  (2)GPIO_Mode_IN_FLOATING 浮空输入
  (3)GPIO_Mode_IPD 下拉输入
  (4)GPIO_Mode_IPU 上拉输入
  (5)GPIO_Mode_Out_OD 开漏输出
  (6)GPIO_Mode_Out_PP 推挽输出
  (7)GPIO_Mode_AF_OD 复用开漏输出
  (8)GPIO_Mode_AF_PP 复用推挽输出
  (一)、IO口工作模式介绍
  下面我将对各种模式的作详细介绍:
  (1)浮空输入模式:
  
  浮空输入模式下,I/O端口的电平信号直接进入输入数据寄存器。也就是说,I/O的电平状态是不确定的,完全由外部输入决定;如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的。所以在要读取外部信号时通常配置IO口为浮空输入模式。
  (2)上拉输入模式:
  
  上拉输入模式下,I/O端口的电平信号直接进入输入数据寄存器。但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平可以保持在高电平;并且在I/O端口输入为低电平的时候,输入端的电平为低电平。
  (3)下拉输入模式:
  
  下拉输入模式下,IO口工作方式刚好和上拉模式相反。I/O端口的电平信号直接进入输入数据寄存器。但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平可以保持在低电平;并且在I/O端口输入为高电平的时候,输入端为高电平。
  (4)模拟输入模式:
  
  模拟输入模式下,I/O端口的模拟信号(电压信号,而非电平信号)直接模拟输入到片上外设模块,比如ADC模块等等。
  (5)推挽输出模式:
  
  推挽输出模式下,通过设置位设置/清除寄存器或者输出数据寄存器的值,控制P-MOS管和N-MOS管的导通来控制IO口输出高电平还是低电平。这里要注意P-MOS管和N-MOS管,当设置输出的值为1的时候,P-MOS管处于开启状态,N-MOS管处于关闭状态,此时I/O端口的电平就由P-MOS管决定为高电平;当设置输出的值为0的时候,P-MOS管处于关闭状态,N-MOS管处于开启状态,此时I/O端口的电平就由N-MOS管决定为低电平。同时,I/O端口的电平也可以通过输入电路进行读取;注意,此时I/O端口的电平一定是输出的电平。
  (6)复用推挽模式
  
  推挽复用输出模式,与推挽输出模式很是类似。只是输出的高低电平的来源,不是让CPU直接写输出数据寄存器,取而代之利用片上外设模块的复用功能输出来决定的。
  (7)开漏输出模式:
  
  开漏输出模式下,通过设置位设置/清除寄存器或者输出数据寄存器的值,控制MOS管的导通。这里要注意N-MOS管,当设置输出的值为高电平的时候,N-MOS管处于关闭状态,此时I/O端口的电平就不会由输出的高低电平决定,而是由I/O端口外部的上拉或者下拉决定;当设置输出的值为低电平的时候,N-MOS管处于开启状态,此时I/O端口的电平就是低电平。同时,I/O端口的电平也可以通过输入电路进行读取;注意,I/O端口的电平不一定是输出的电平。通常使用开漏输出时外部要加一个上拉电阻。
  (8)复用开漏输出模式:
  
  开漏复用输出模式,与开漏输出模式很是类似。只是输出的高低电平的来源,不是让CPU直接写输出数据寄存器,取而代之利用片上外设模块的复用功能输出来决定的。
  (二)、常用IO口模式分析
  对于刚入门的新手,我想这几个概念是必须得搞清楚的,平时接触的最多的也就是推挽输出、开漏输出、上拉输入这三种,但一直未曾对这些做过归纳。因此,在这里做一个总结:
  1、推挽输出:可以输出高,低电平,连接数字器件; 推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源低定。
  推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。
  详细理解:
  推挽放大器的输出级有两个“臂”(两组放大元件),一个“臂”的电流增加时,另一个“臂”的电流则减小,二者的状态轮流转换。对负载而言,好像是一个“臂”在推,一个“臂”在拉,共同完成电流输出任务。当输出高电平时,也就是下级负载门输入高电平时,输出端的电流将是下级门从本级电源经VT3拉出。这样一来,输出高低电平时,VT3 一路和 VT5 一路将交替工作,从而减低了功耗,提高了每个管的承受能力。又由于不论走哪一路,管子导通电阻都很小,使RC常数很小,转变速度很快。因此,推拉式输出级既提高电路的负载能力,又提高开关速度。
  2、开漏输出:输出端相当于三极管的集电极。 要得到高电平状态需要上拉电阻才行。 适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。
  开漏形式的电路有以下几个特点:
  a. 利用外部电路的驱动能力,减少IC内部的驱动。当IC内部MOSFET导通时,驱动电流是从外部的VCC流经R pull-up ,MOSFET到GND。IC内部仅需很下的栅极驱动电流。
  b. 一般来说,开漏是用来连接不同电平的器件,匹配电平用的,因为开漏引脚不连接外部的上拉电阻时,只能输出低电平,如果需要同时具备输出高电平的功能,则需要接上拉电阻,很好的一个优点是通过改变上拉电源的电压,便可以改变传输电平。比如加上上拉电阻就可以提供TTL/CMOS电平输出等。(上拉电阻的阻值决定了逻辑电平转换的沿的速度 。阻值越大,速度越低功耗越小,所以负载电阻的选择要兼顾功耗和速度。)
  c. OPEN-DRAIN提供了灵活的输出方式,但是也有其弱点,就是带来上升沿的延时。因为上升沿是通过外接上拉无源电阻对负载充电,所以当电阻选择小时延时就小,但功耗大;反之延时大功耗小。所以如果对延时有要求,则建议用下降沿输出。
  d. 可以将多个开漏输出的Pin,连接到一条线上。通过一只上拉电阻,在不增加任何器件的情况下,形成“与逻辑”关系。这也是I2C,SMBus等总线判断总线占用状态的原理。
  e.补充:什么是“线与”?:
  在一个结点(线)上, 连接一个上拉电阻到电源 VCC 或 VDD 和 n 个 NPN 或 NMOS 晶体管的集电极 C 或漏极 D, 这些晶体管的发射极 E 或源极 S 都接到地线上, 只要有一个晶体管饱和, 这个结点(线)就被拉到地线电平上。 因为这些晶体管的基极注入电流(NPN)或栅极加上高电平(NMOS), 晶体管就会饱和, 所以这些基极或栅极对这个结点(线)的关系是或非 NOR 逻辑。 如果这个结点后面加一个反相器, 就是或 OR 逻辑。
  其实可以简单的理解为:在所有引脚连在一起时,外接一上拉电阻,如果有一个引脚输出为逻辑0,相当于接地,与之并联的回路“相当于被一根导线短路”,所以外电路逻辑电平便为0,只有都为高电平时,与的结果才为逻辑1。
  3、浮空输入:对于浮空输入,由于浮空输入一般多用于外部按键输入,结合图上的输入部分电路,我理解为浮空输入状态下,IO的电平状态是不确定的,完全由外部输入决定,如果在该引脚悬空的情况下,读取该端口的电平是不确定的。
  (三)实际应用
  (1) 浮空输入_IN_FLOATING ——浮空输入,可以做KEY识别,RX1
  (2)带上拉输入_IPU——IO内部上拉电阻输入
  (3)带下拉输入_IPD—— IO内部下拉电阻输入
  (4) 模拟输入_AIN ——应用ADC模拟输入,或者低功耗下省电
  (5)开漏输出_OUT_OD ——IO输出0接GND,IO输出1,悬空,需要外接上拉电阻,才能实现输出高电平。当输出为1时,IO口的状态由上拉电阻拉高电平,但由于是开漏输出模式,这样IO口也就可以由外部电路改变为低电平或不变。可以读IO输入电平变化,实现C51的IO双向功能
  (6)推挽输出_OUT_PP ——IO输出0-接GND, IO输出1 -接VCC,读输入值是未知的
  (7)复用功能的推挽输出_AF_PP ——片内外设功能(I2C的SCL,SDA)
  (8)复用功能的开漏输出_AF_OD——片内外设功能(TX1,MOSI,MISO.SCK.SS)
  STM32设置实例
  (1)模拟I2C使用开漏输出_OUT_OD,接上拉电阻,能够正确输出0和1;读值时先GPIO_SetBits(GPIOB, GPIO_Pin_0);拉高,然后可以读IO的值;使用GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0);
  (2)如果是无上拉电阻,IO默认是高电平;需要读取IO的值,可以使用带上拉输入_IPU和浮空输入_IN_FLOATING和开漏输出_OUT_OD;
  通常有5种方式使用某个引脚功能,它们的配置方式如下:
  1)作为普通GPIO输入:根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时不要使能该引脚对应的所有复用功能模块。
  2)作为普通GPIO输出:根据需要配置该引脚为推挽输出或开漏输出,同时不要使能该引脚对应的所有复用功能模块。
  3)作为普通模拟输入:配置该引脚为模拟输入模式,同时不要使能该引脚对应的所有复用功能模块。
  4)作为内置外设的输入:根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时使能该引脚对应的某个复用功能模块。
  5)作为内置外设的输出:根据需要配置该引脚为复用推挽输出或复用开漏输出,同时使能该引脚对应的所有复用功能模块。
  按键
  #define KEY0 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) //读取按键 0
  #define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) //读取按键 1
  #define KEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) //读取按键 2
  #define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) //读取按键 3(WK_UP)
  时钟树
  
  
  
  Systick定时器--用作延时或实时系统的心跳时钟
  
  使用要先初始化 delay_init();
  
  串口通信
  
  实验5.外部中断
  
  
  中断文件
  #include “exti.h”
  #include “led.h”
  #include “key.h”
  #include “delay.h”
  #include “usart.h”
  #include “beep.h”
  //
  //本程序只供学习使用,未经作者许可,不得用于其它任何用途
  //ALIENTEK战舰STM32开发板
  //外部中断 驱动代码
  //
  //外部中断0服务程序
  void EXTIX_Init(void)
  {
  EXTI_InitTypeDef EXTI_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  KEY_Init(); // 按键端口初始化
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟
  //GPIOE.2 中断线以及中断初始化配置 下降沿触发
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);
  EXTI_InitStructure.EXTI_Line=EXTI_Line2; //KEY2
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
  //GPIOE.3 中断线以及中断初始化配置 下降沿触发 //KEY1
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
  EXTI_InitStructure.EXTI_Line=EXTI_Line3;
  EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
  //GPIOE.4 中断线以及中断初始化配置 下降沿触发 //KEY0
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);
  EXTI_InitStructure.EXTI_Line=EXTI_Line4;
  EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
  //GPIOA.0 中断线以及中断初始化配置 上升沿触发 PA0 WK_UP
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
  EXTI_InitStructure.EXTI_Line=EXTI_Line0;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键WK_UP所在的外部中断通道
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);
  NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //使能按键KEY2所在的外部中断通道
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);
  NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //使能按键KEY1所在的外部中断通道
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级1
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
  NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
  NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //使能按键KEY0所在的外部中断通道
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //子优先级0
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
  NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
  }
  //外部中断0服务程序
  void EXTI0_IRQHandler(void)
  {
  delay_ms(10);//消抖
  if(WK_UP==1) //WK_UP按键
  {
  BEEP=!BEEP;
  }
  EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位
  }
  //外部中断2服务程序
  void EXTI2_IRQHandler(void)
  {
  delay_ms(10);//消抖
  if(KEY2==0) //按键KEY2
  {
  LED0=!LED0;
  }
  EXTI_ClearITPendingBit(EXTI_Line2); //清除LINE2上的中断标志位
  }
  //外部中断3服务程序
  void EXTI3_IRQHandler(void)
  {
  delay_ms(10);//消抖
  if(KEY1==0) //按键KEY1
  {
  LED1=!LED1;
  }
  EXTI_ClearITPendingBit(EXTI_Line3); //清除LINE3上的中断标志位
  }
  void EXTI4_IRQHandler(void)
  {
  delay_ms(10);//消抖
  if(KEY0==0) //按键KEY0
  {
  LED0=!LED0;
  LED1=!LED1;
  }
  EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中断标志位
  }
  main.c
  int main(void)
  {
  delay_init(); //延时函数初始化
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
  uart_init(115200); //串口初始化为115200
  LED_Init(); //初始化与LED连接的硬件接口
  BEEP_Init(); //初始化蜂鸣器端口
  KEY_Init(); //初始化与按键连接的硬件接口
  EXTIX_Init(); //外部中断初始化
  LED0=0; //点亮LED0
  while(1)
  {
  printf(“OKrn”);
  delay_ms(1000);
  }
  }
举报

更多回帖

发帖
×
20
完善资料,
赚取积分