Skip to content

problemSolved

Crabor edited this page Oct 12, 2019 · 10 revisions

疑难解决

2019.7.25

蓝牙模块通信

大二下学期期末考完试后爆肝四轴,本来把上个学期的东西一个一个的都加进来了,蓝牙模块通信也差不多了,能够实现板子发送数据以及电脑串口助手接收数据,但是却是乱码。我一开始以为是因为中文的原因,但是换成printf("Hello STM32!\n")也不行,也是乱码。。。。

于是我尝试换一个串口,从usart2usart3再到usart6,结果都是错误的,错的还都一样。今天突然看了看自己写的串口驱动程序,再三检查程序本身是没有问题,但是否调用程序是参数出错?原来我在BSP.c中调用串口初始化写的是:

uart6_init(42,9600);//para1:PCLK2时钟频率(Mhz),para2:波特率

我才恍然大悟,其实是自己这里的pclk2时钟频率和对时钟树配置的频率没有对应上,在BSP_SELF/system_stm32f4xx.c文件里面我通过设置让APB2总线的频率是84MHz,但是这里自己调用时却是42MHz。更改之后就解决问题啦!

最后总结一下如果串口直连通信正常但是换成蓝牙后就出问题的检查解决步骤:

  1. 查看蓝牙AT指令对于蓝牙波特率的设置,一定要确保板子、蓝牙、串口助手三者的波特率一致,不然就会出现乱码。

  2. 检查串口的频率是否和自己在system_stm32f4xx.cSetSysClock()里面设置的内容一致。

关于STM32F4板子时钟树的知识以及步骤点击这里查看

2019.9.10

串口中断通信

请先查看串口中断通信重点知识点击这里查看

在将串口通信方式从 重定向fputc函数用printf输出 到 用发送中断进行输出 的路上遇到很多坑:一是电脑只接收到一个字节的数据,原本应该接收到一个完整数组的全部内容;而是一个数据都没有接收到。

针对只接收到一个字节的数据,我的usart.c的核心源码为

//初始化IO 串口6
//pclk2:PCLK2时钟频率(Mhz)
//bound:波特率
void uart6_init(u32 pclk2,u32 bound)
{   //PC6,PC7
    float temp;
    u16 mantissa;
    u16 fraction;
    temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV@OVER8=0
    mantissa=temp;         //得到整数部分
    fraction=(temp-mantissa)*16; //得到小数部分@OVER8=0
    mantissa<<=4;
    mantissa+=fraction;
    RCC->AHB1ENR|=1<<2; //使能PORTC口时钟
    RCC->APB2ENR|=1<<5; //使能串口6时钟
    GPIO_Set(GPIOC,GPIO_Pin_6|GPIO_Pin_7,GPIO_Mode_AF,GPIO_OType_PP,GPIO_Speed_50MHz,GPIO_PuPd_UP);//PC6,PC7,复用功能,上拉输出
    GPIO_AF_Set(GPIOC,6,8);  //PC6,AF8
    GPIO_AF_Set(GPIOC,7,8);//PC7,AF8
    //波特率设置
    USART6->BRR=mantissa;   //波特率设置
    USART6->CR1&=~(1<<15);   //设置OVER8=0
    USART6->CR1|=1<<3;    //串口发送使能
    //使能接收中断
//    USART6->CR1|=1<<2;    //串口接收使能
//    USART6->CR1|=1<<5;      //接收缓冲区非空中断使能
    MY_NVIC_Init(3,3,USART6_IRQn,2);//组2,最低优先级
    USART6->CR1|=1<<13;    //串口使能
}

u8 FLAG_TC=0;//定义全局变量

void Usart6_IRQ ( void ){
 if (USART_GetITStatus(USART6, USART_IT_TC) != RESET)//发送完成中断,= SET
  {
    USART_ClearITPendingBit(USART6,USART_IT_TC);
    FLAG_TC=1;
  }
}

//DataToSend:发送数组
//data_num:数组长度
void Usart6_Send ( u8 *DataToSend , u8 data_num ){
  u8 i=0;
  FLAG_TC=0;//提前准备一下
  for(i=0;i<data_num;i++)//检测字符串结束符
  {
    USART_SendData(USART6 ,*(DataToSend+i));//发送当前字符
    while( FLAG_TC==0);  //0:发送还未完成;1:发送完成
    FLAG_TC=0;
  }
}

在main.c中我通过调用Usart6_Send函数发送我想要发送的数组内容,然而结果只是接收到第一个字节的内容,这是因为在Usart6_Send函数中一直卡在了while( FLAG_TC==0);循环中。这是因为FLAG_TC的值一直为零,而这就说明了串口中断(Usart6_IRQ)一直没有被触发,推及原因自然就是发送中断未使能,从而导致在执行完USART_SendData(USART6 ,*(DataToSend+i));后没有触发发送中断。

针对一个字节的数据都没接收到,我的usart.c的核心源码为

//初始化IO 串口6
//pclk2:PCLK2时钟频率(Mhz)
//bound:波特率
void uart6_init(u32 pclk2,u32 bound)
{   //PC6,PC7
    float temp;
    u16 mantissa;
    u16 fraction;
    temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV@OVER8=0
    mantissa=temp;         //得到整数部分
    fraction=(temp-mantissa)*16; //得到小数部分@OVER8=0
    mantissa<<=4;
    mantissa+=fraction;
    RCC->AHB1ENR|=1<<2; //使能PORTC口时钟
    RCC->APB2ENR|=1<<5; //使能串口6时钟
    GPIO_Set(GPIOC,GPIO_Pin_6|GPIO_Pin_7,GPIO_Mode_AF,GPIO_OType_PP,GPIO_Speed_50MHz,GPIO_PuPd_UP);//PC6,PC7,复用功能,上拉输出
    GPIO_AF_Set(GPIOC,6,8);  //PC6,AF8
    GPIO_AF_Set(GPIOC,7,8);//PC7,AF8
    //波特率设置
    USART6->BRR=mantissa;   //波特率设置
    USART6->CR1&=~(1<<15);   //设置OVER8=0
    USART6->CR1|=1<<3;    //串口发送使能
    //使能接收中断
//    USART6->CR1|=1<<2;    //串口接收使能
//    USART6->CR1|=1<<5;      //接收缓冲区非空中断使能
    MY_NVIC_Init(3,3,USART6_IRQn,2);//组2,最低优先级
    USART6->CR1|=1<<13;    //串口使能
    USART6->CR1|=1<<6;    //发送中断使能
}

u8 FLAG_TC=0;//定义全局变量

void Usart6_IRQ ( void ){
 if (USART_GetITStatus(USART6, USART_IT_TC) != RESET)//发送完成中断,= SET
  {
    USART_ClearITPendingBit(USART6,USART_IT_TC);
    FLAG_TC=1;
  }
}

//DataToSend:发送数组
//data_num:数组长度
void Usart6_Send ( u8 *DataToSend , u8 data_num ){
  u8 i=0;
  FLAG_TC=0;//提前准备一下
  for(i=0;i<data_num;i++)//检测字符串结束符
  {
    USART_SendData(USART6 ,*(DataToSend+i));//发送当前字符
    while( FLAG_TC==0);  //0:发送还未完成;1:发送完成
    FLAG_TC=0;
  }
}

在main.c中我通过调用Usart6_Send函数发送我想要发送的数组内容,然而结果一个字节都未收到,这是因为我在串口初始化函数中使能了发送中断(TCIE)。查阅资料发现,在使能了发送完成中断之后,硬件就会紧接着发送一个空字符,那么发送完成之后就进入了中断服务函数了,而这次进入中断并不是我们想要的,所以在串口初始化函数中不应该使能发送中断。

解决方案就是不在串口初始化函数中使能发送中断,而是在发送数据的函数中使能发送中断,修改后我的usart.c的核心源码为:

//初始化IO 串口6
//pclk2:PCLK2时钟频率(Mhz)
//bound:波特率
void uart6_init(u32 pclk2,u32 bound)
{   //PC6,PC7
    float temp;
    u16 mantissa;
    u16 fraction;
    temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV@OVER8=0
    mantissa=temp;         //得到整数部分
    fraction=(temp-mantissa)*16; //得到小数部分@OVER8=0
    mantissa<<=4;
    mantissa+=fraction;
    RCC->AHB1ENR|=1<<2; //使能PORTC口时钟
    RCC->APB2ENR|=1<<5; //使能串口6时钟
    GPIO_Set(GPIOC,GPIO_Pin_6|GPIO_Pin_7,GPIO_Mode_AF,GPIO_OType_PP,GPIO_Speed_50MHz,GPIO_PuPd_UP);//PC6,PC7,复用功能,上拉输出
    GPIO_AF_Set(GPIOC,6,8);  //PC6,AF8
    GPIO_AF_Set(GPIOC,7,8);//PC7,AF8
    //波特率设置
    USART6->BRR=mantissa;   //波特率设置
    USART6->CR1&=~(1<<15);   //设置OVER8=0
    USART6->CR1|=1<<3;    //串口发送使能
    //使能接收中断
//    USART6->CR1|=1<<2;    //串口接收使能
//    USART6->CR1|=1<<5;      //接收缓冲区非空中断使能
    MY_NVIC_Init(3,3,USART6_IRQn,2);//组2,最低优先级
    USART6->CR1|=1<<13;    //串口使能
}


u8 FLAG_TC=0;//定义全局变量

void Usart6_IRQ ( void ){
 if (USART_GetITStatus(USART6, USART_IT_TC) != RESET)//发送完成中断,= SET
  {
    USART_ClearITPendingBit(USART6,USART_IT_TC);
    FLAG_TC=1;
  }
}

//DataToSend:发送数组
//data_num:数组长度
void Usart6_Send ( u8 *DataToSend , u8 data_num ){
  u8 i=0;
  FLAG_TC=0;//提前准备一下
  for(i=0;i<data_num;i++)//检测字符串结束符
  {
    USART_SendData(USART6 ,*(DataToSend+i));//发送当前字符
    if(!(USART6->CR1 & USART_CR1_TCIE))//判断USART6->CR1中的TCIE位是否设置,即“发送完成中断”是否使能
    {
        USART_ITConfig(USART6, USART_IT_TC, ENABLE);
    }
    while( FLAG_TC==0);  //0:发送还未完成;1:发送完成
    FLAG_TC=0;
  }
}

在发送完数组第一个字节后SR寄存器中的TC位为1,接着使能发送中断让CR1寄存器中的TCIE位为1,于是触发中断,FLAG_TC值变成1,之后跳出while( FLAG_TC==0);循环,再接着发送下一个字节数据。在发送完下一个数据后,SR寄存器中的TC位又被置1,于是又触发了中断将FLAG_TC置1(因为上一次已经使能了发送中断,所以第二次并没有使能发送中断)······值得一提的是在USART_SendData函数会执行USARTx->DR的写操作,这个写操作的同时会自动将SR寄存器中的TC位清零,所以就不要疑惑不知道在哪里将TC位置1了。

2019.10.12

定时器5的通道34输入捕获

问题解决了,原来不是硬件bug,也不是我代码问题,而是焊桥问题233333。

结合说明书,板子默认SB62、SB63是关闭的,而SB13、SB14是开启的。也就是说,就算我将PWM波的信号线往PA2、PA3引脚怼,也不会将信号传到STM32 MCU上,因为PA2、PA3实际是和STLink MCU相连的,用于虚拟串口。所以如果要取消PA2、PA3虚拟串口的功能而实现接收PWM波功能,就需要将SB62、SB63开启的、SB13、SB14关闭。