第0章:前言
- 此次智能小车设计是从0开始设计涉及多个模块
- 此文章中不仅包含制作过程,也包含制作过程中遇到的一些问题及解决方法。
- 如果不设置时钟的话,系统默认时钟是72MHz,在system_stm32f10x.c文件中有定义(#define SYSCLK_FREQ_72MHz 72000000)
第一章:让小车动起来
涉及知识点及模块
- 涉及模块:二路BTN驱动模块、LM317可调稳压模块
- PWM调速:给电机正负极通电可以直接使电机转动起来,但是控制电机转动速度就需要到PWM了。当设置通电的占空比越小(通电时间与一个周期的比值),电机表现出的现象就是转速降低。
- 正反转:将电机上两接线反接即可。
- 预分频值Precaler = 主频÷时钟频率-1(分频后的频率);72000000÷10000=7200-1
- 计数周期Period = 时钟频率÷目标频率-1
- PWM初始化程序如下:这里使用的是TIM2的通道3作为pwm输出(PA2接A1,PA3接A2)
- A1/A2/B1/B2是指驱动模块上的接口。
实验代码
void pwm_init_left(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量,用来初始化GPIO
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//声明一个结构体变量,用来初始化定时器
TIM_OCInitTypeDef TIM_OCInitStructure;//根据TIM_OCInitStruct中指定的参数初始化外设TIMx
/* 开启时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
/* 配置GPIO的模式和IO口 PA2*/
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure);
// T = CNT/fHz = 9000/72000000s
// Period = 时钟频率÷目标频率-1
// 预分频值:Precaler = 主频÷目标频率-1(分频后的频率);72000000÷10000=7200-1
//TIM2定时器初始化
TIM_TimeBaseInitStructure.TIM_Period = 99; //周期,不分频,设置自动重装载寄存器周期的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 719;//设置用来作为TIMx时钟频率预分频值(主频÷目标频率-1)。
TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;//设置时钟分割:
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM2, & TIM_TimeBaseInitStructure);
// 将TIM2的输出引脚进行fll remap到PA15,也就是P3.7
//GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);
//PWM初始化 //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//PWM输出使能
TIM_OCInitStructure.TIM_Pulse = 50;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC3Init(TIM2,&TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM2,ENABLE);
TIM_Cmd(TIM2,ENABLE);//使能TIMx外设
}
遇到的问题
- 第一次使用J_Link需要安装J_Link的驱动,这个直接下载<驱动精灵>软件,它会自动检测缺少的驱动,下载安装即可。
- 在使用J_link调试时注意要先下载一次程序后再用J_link。我的是出现这种情况,其他人的不知道。(在一刚开始调试程序时,电机能转但是调不了速,就是因为这个情况)
- TIM_OCInitStructure.TIM_Pulse的值不能设置过小,否则电机不会转动,设置为40时就不会转动(这里存在另一个问题,就是设置的值超过50之后,电机转速差不多,也就是无法改变速度)
- 还有一个问题就是这种方法无法改变电机正反转,因为这里只使用了一个通道。
问题解决方案
- 首先TIM_Pulse的值不能设置过小的问题:经检测是TIM_Period周期的值设置过小,频率太高,电机没有那么好的性能。可以将TIM_Period周期设置为7200-1,频率为10khz。
- 然后就是电机正反转的问题:可以利用同一个定时器的四个不同通道(OC1/2/3/4),分别接到A1/A2/B1/B2上,然后分别设置四个通道的比较寄存器的值即可实现正反转(例如将OC1的比较值设置为5000,OC2的比较值设置为0即可正转;反之即可反转)
- 这里如果像上面那样写的话,四个通道要写很多代码,所以这里做了一点改变。
- 这里设置比较寄存器中的值运用到了库函数中的TIM_SetCompare_x函数。
/** * @brief Sets the TIMx Capture Compare1 Register value * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral. * @param Compare1: specifies the Capture Compare1 register new value. * @retval None */ void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1) { /* Check the parameters */ assert_param(IS_TIM_LIST8_PERIPH(TIMx)); /* Set the Capture Compare1 Register value */ TIMx->CCR1 = Compare1; }
解决方案代码
//PA0-4,用于PWM输出
void PWM_TIM_2_Init(u16 Period,u16 Prescaler)
{
GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量,用来初始化GPIO
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//声明一个结构体变量,用来初始化定时器
TIM_OCInitTypeDef TIM_OCInitStructure;//根据TIM_OCInitStruct中指定的参数初始化外设TIMx
/* 开启时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
/* 配置GPIO的模式和IO口 PA0 1 2 3*/
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure);
// T = CNT/fHz = 9000/72000000s
// Period = 时钟频率÷目标频率-1
// 预分频值:Precaler = 主频÷时钟频率-1(分频后的频率);72000000÷10000=720-1
//TIM3定时器初始化
TIM_TimeBaseInitStructure.TIM_Period = Period; //周期,不分频,设置自动重装载寄存器周期的值
TIM_TimeBaseInitStructure.TIM_Prescaler = Prescaler;//设置用来作为TIMx时钟频率预分频值(主频÷目的频率-1)
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//设置时钟分割:
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM2, & TIM_TimeBaseInitStructure);
// 将TIM2的输出引脚进行fll remap到PA15,也就是P3.7
//GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);
//PWM初始化 //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//PWM输出使能
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2,&TIM_OCInitStructure);
TIM_OC2Init(TIM2,&TIM_OCInitStructure);
TIM_OC3Init(TIM2,&TIM_OCInitStructure);
TIM_OC4Init(TIM2,&TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM2,ENABLE); //TIM2在ARR上预装载寄存器使能
TIM_Cmd(TIM2,ENABLE); //使能TIMx外设
}
int main(void)
{
PWM_TIM_2_Init(7199,0);
//正转
TIM_SetCompare1(TIM2,5000);
TIM_SetCompare2(TIM2,0);
//反转
TIM_SetCompare3(TIM2,0);
TIM_SetCompare4(TIM2,3000);
while(1)
{
}
}
第二章:测量小车转速(编码器)
光电编码器
电机接线图:
- 光电编码器输出的是正弦波,A相和B相都是输出正弦波。
- 当A相为上升沿时,B相若为低电平,电机正转。
- 当A相为上升沿时,B相若为高电平,电机反转。
- 注意:由于我这里只捕获A相的上升沿,所以AB相的线不能接反了,否则TIM3的通道1的中断触发不了。
输入捕获
- 功能:用于测量输入信号的脉宽、测量 PWM 输入信号的频率及占空比。
实现流程:
- 首先配置某个定时器为计数器模式(计数器的频率必须远大于输入的频率)
- 然后再配置该定时器的一个通道作为捕获通道(配置为上升沿检测或下降沿检测)
- 当这个通道检测到对应的边沿时,就会触发该通道的中断(此时计数器的值会自动加载到捕获比较寄存器中)
- 输入波形的周期 = 相邻两个捕获寄存器值之差 * 计数器的周期值。
实验代码
u8 i = 0; //标志第一次还是第二次检测到上升沿
u16 BianMaQi_speed_ZUO = 0; //编码器的输出1个周期时,定时器的计数值
u16 BianMaQi_speed_YOU = 0;
u8 zhen_fan_zhuan_ZUO = 0; //标志电机正转还是反转(1正0反)
u8 zhen_fan_zhuan_YOU = 0;
u16 zhuan_su_ZUO = 0; //小车转速r/min
u16 zhuan_su_YOU = 0;
double BianMaQi_ZUO_zhouqi = 0.0;//编码器的周期
double BianMaQi_YOU_zhouqi = 0.0;
/*******************************************************************************
* 函 数 名 : TIM3_CH1_Input_Init(使用TIM3的 通道1 PA6 接左轮A相 和 通道2 PA7 接左轮B相)
* 函数参数 :arr:自动重装载值; psc:预分频系数
* 函数返回值 :无
* 函数功能 : TIM3_CH1输入捕获初始化函数(只捕获通道1的波形)
*******************************************************************************/
void TIM3_CH1_Input_Init(u16 Period,u16 Prescaler)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM3时钟
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;//管脚设置
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //设置上拉输入模式
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
TIM_TimeBaseInitStructure.TIM_Period=Period; //自动装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=Prescaler; //分频系数
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; //通道1
TIM_ICInitStructure.TIM_ICFilter=0x00; //无滤波
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕获极性
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频系数
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1
TIM_ICInit(TIM3,&TIM_ICInitStructure);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
TIM_ITConfig(TIM3,TIM_IT_CC1,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;//中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3,ENABLE); //使能定时器
}
/*******************************************************************************
* 函 数 名 : TIM3_IRQHandler
* 函数参数 :无
* 函数返回值 :无
* 函数功能 : TIM3中断函数(读取TIM3计数器的值,并检测电机是正转还是反转)
*******************************************************************************/
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_CC1) == 1) //检测TIM3的通道1是否发生中断
{
if(TIM_GetFlagStatus(TIM3,TIM_FLAG_CC1))
{
BianMaQi_speed_ZUO = TIM_GetCounter(TIM3) - BianMaQi_speed_ZUO;
BianMaQi_ZUO_zhouqi = BianMaQi_speed_ZUO * 1/1000000; //计算编码器的周期
zhuan_su_ZUO = BianMaQi_ZUO_zhouqi * 500; //小车转速r/min
i++;
}
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7) == 0) //A相为上升沿,B相为0,正转
{
zhen_fan_zhuan_ZUO = 1;
}
else
{
zhen_fan_zhuan_ZUO = 0;
}
if(i==2)
{
TIM_SetCounter(TIM3,0); //定时器3的计数器清零
TIM_Cmd(TIM3,ENABLE); //使能定时器3
BianMaQi_speed_ZUO = 0;
i = 0;
}
TIM_ClearITPendingBit(TIM3,TIM_IT_CC1|TIM_IT_Update); //清除TIMx的中断挂起位
}
}
/*******************************************************************************
* 函 数 名 : TIM4_CH3_Input_Init(使用TIM4的 通道3 PB8 接右轮A相 和 通道2 PB9 接右轮B相)
* 函数参数 :arr:自动重装载值; psc:预分频系数
* 函数返回值 :无
* 函数功能 : TIM4_CH3输入捕获初始化函数(只捕获通道3的波形)
*******************************************************************************/
void TIM4_CH3_Input_Init(u16 Period,u16 Prescaler)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//使能TIM4时钟
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9;//管脚设置
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //设置上拉输入模式
GPIO_Init(GPIOB,&GPIO_InitStructure); /* 初始化GPIO */
TIM_TimeBaseInitStructure.TIM_Period=Period; //自动装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=Prescaler; //分频系数
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_3; //通道1
TIM_ICInitStructure.TIM_ICFilter=0x00; //无滤波
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕获极性
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频系数
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1
TIM_ICInit(TIM4,&TIM_ICInitStructure);
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
TIM_ITConfig(TIM4,TIM_IT_CC3,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;//中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM4,ENABLE); //使能定时器
}
/*******************************************************************************
* 函 数 名 : TIM4_IRQHandler
* 函数参数 :无
* 函数返回值 :无
* 函数功能: : TIM4中断函数(读取TIM4计数器的值,并检测电机是正转还是反转)
*******************************************************************************/
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_CC3) == 1) //检测TIM3的通道1是否发生中断
{
if(TIM_GetFlagStatus(TIM4,TIM_FLAG_CC3))
{
BianMaQi_speed_YOU = TIM_GetCounter(TIM4) - BianMaQi_speed_YOU;
BianMaQi_YOU_zhouqi = BianMaQi_speed_YOU * 1/1000000; //计算编码器的周期
zhuan_su_YOU = BianMaQi_YOU_zhouqi * 500; //小车转速r/min
i++;
}
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9) == 0) //A相为上升沿,B相为0,正转
{
zhen_fan_zhuan_YOU = 1;
}
else
{
zhen_fan_zhuan_YOU = 0;
}
if(i==2)
{
TIM_SetCounter(TIM4,0); //定时器3的计数器清零
TIM_Cmd(TIM4,ENABLE); //使能定时器3
BianMaQi_speed_YOU = 0;
i = 0;
}
TIM_ClearITPendingBit(TIM4,TIM_IT_CC3|TIM_IT_Update); //清除TIMx的中断挂起位
}
}
遇到的问题
在mian函数中引用两个输入捕获初始化函数后(TIM3_CH1_Input_Init和TIM4_CH3_Input_Init) ,再引用设置比较寄存器函数TIM_SetCompare1时,电机不转动。经过测试是输入捕获初始化函数有问题(在此函数之前使用TIM_SetCompare1时,电机能够转动)
- 代码示例
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组 PWM_TIM_2_Init(7199,0); TIM3_CH1_Input_Init(0xffff,0); TIM4_CH3_Input_Init(0xffff,0); TIM_SetCompare1(TIM2,0); TIM_SetCompare2(TIM2,5000); TIM_SetCompare3(TIM2,0); TIM_SetCompare4(TIM2,5000); while(1) { } }
解决方案
- 将TIM3_CH1_Input_Init函数中的中断嵌套NVIC设置关闭即可。
/*******************************************************************************
* 函 数 名 : TIM3_CH1_Input_Init(使用TIM3的 通道1 PA6 接左轮A相 和 通道2 PA7 接左轮B相)
* 函数参数 :arr:自动重装载值; psc:预分频系数
* 函数返回值 :无
* 函数功能 : TIM3_CH1输入捕获初始化函数(只捕获通道1的波形)
*******************************************************************************/
void TIM3_CH1_Input_Init(u16 Period,u16 Prescaler)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
//NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM3时钟
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;//管脚设置
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //设置上拉输入模式
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
TIM_TimeBaseInitStructure.TIM_Period=Period; //自动装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=Prescaler; //分频系数
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; //通道1
TIM_ICInitStructure.TIM_ICFilter=0x00; //无滤波
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕获极性
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频系数
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1
TIM_ICInit(TIM3,&TIM_ICInitStructure);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
TIM_ITConfig(TIM3,TIM_IT_CC1,ENABLE);
//NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;//中断通道
//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
//NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级
//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
//NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3,ENABLE); //使能定时器
}
第三章:蓝牙模块的加入
- 配置USART串口,用单片机的USART1_TX连接RXD,USART1_RX连接TXD。
- 注意:蓝牙的波特率必须与串口的相同。
- 关于串口的相关问题看另一篇文章:https://segmentfault.com/a/11...
遇到的问题及解决方法
- 问题:在配置完串口后,手机连接蓝牙,结果出现乱码(这应该都是串口的常出问题了吧)
- 问题所在:波特率不匹配。
- 解决办法:进过检测,蓝牙模块的默认波特率是9600,虽然在设置串口波特率时我已经设置为9600了,但是任然出现乱码。原因是库默认使用8MHz晶振,可以通过宏使用25MHz或12M晶振;具体定义在stm32f10x.h文件中,HSE_VALUE一开始定义成了8000000,改成12000000搞定,串口通信就可以显示正常。
代码示例
#include "usart.h"
unsigned char Data;
/*******************************************************************************
* 函 数 名 : USART1_Init
* 函数功能 : USART1初始化函数
* 输 入 : bound:波特率
* 输 出 : 无
*******************************************************************************/
void USART1_Init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //打开时钟
/* 配置GPIO的模式和IO口 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX //串口输出PA9
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入IO */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX //串口输入PA10
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
//USART1 初始化设置
USART_InitStructure.USART_BaudRate = bound;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1
USART_ClearFlag(USART1, USART_FLAG_TC);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
}
/*******************************************************************************
* 函 数 名 : USART1_IRQHandler
* 函数功能 : USART1中断函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void USART1_IRQHandler(void) //串口1中断服务程序
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
Data = USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
USART_SendData(USART1,Data);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);
}
USART_ClearFlag(USART1,USART_FLAG_TC);
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。