记录基于STM32的独轮车测试板构建(三)PCB篇

PCB布线过程就不分享了,笔者是野路子没有系统的学习,都是连上能用就行。本篇书接上回记录一下测试版的后续。几天打板,买材料,焊接之后,组装上车

板子焊好装车后的照片

 虽然板子主要功能测试都符合预期,但还是有一些意料之外的问题。首先是供电部分,创新的单开关控制两路电源,又犯了野路子常见的错误,MOS管的导通条件VGS是G相对于S的电压,而不是相对于GND的电压。

单开关双电源原理图

 从原理图其实已经能看出问题了,理想中的导通状态MOS的S极是24V,而G是12V,VGS甚至小于0,当然不可能实现。这个电路实际的效果是,12V上电一瞬间,24V的负载端电压为0,所以MOS是会导通的,但随着24V电路上电,电压上升到10V时,VGS已经只有2V,MOS要截止了,但如果MOS截止后端的电压又会降下去,VGS又变大了,MOS就导通,于是MOS就卡在VGS=2V这么一个只导通了一点点的状态,而24V端的电压也只能上升到10V,且此时MOS的导通电阻应当是非常大的,完全不可用。正确的设计应当把MOS放在24V的负极端

符合预期的原理图

 由于GND永远是0V,所以只要12V到位了,MOS就一直导通,而12V撤去后VGS就是0,也就截止,24V无法形成对地回路也就无法工作。三极管和MOS管错误放在正极的经历已经有好几次,希望这次踩坑可以从此杜绝这种情况。

这块板在调试的过程中还遇到了一个小问题,STM32会不定期不能正常工作,可以进入调试模式,但调试模式下一步根本进不了main.c,看到这里屏幕前熟悉STM32的朋友一定想到了,肯定是进bootloader了。我第一时间也是这么想的,但很快否定了这种猜想,因为据我所知STM32G4系列没有bootloader,我用过不少G030,第一次搜索了解到G系列的bootloader需要特殊操作去启用才有作用,所以G030从没管过boot,也从没出现过异常进入boot的情况。我的代码是STM32cubemx自动生成,代码肯定不会有问题,那么排除了boot那就要考虑硬件启动失败,每一路供电的滤波电容都给到了,那么还有啥,复位键是否异常,测量了复位的电平,按下低电平,松开高电平,非常稳定,复位的滤波电容也起作用了。至此就毫无思路了,只好去求助于万能的人均月入20k的群友。果然人外有人,群友一下指出,G4是有boot引脚的,工作条件和F1,F4一样,只是在PB8。我一看cubemx的引脚配置,PB8果然后面有跟着BOOT的字样,大意了。还好PB8作为编码器接口引出了,飞了一个10k上拉,稳定启动,问题解决。

总的来说,板子基本符合预期,一些小瑕疵也可以通过飞线补救,能用就行。小调了一下底层代码,马上搞一个调试保护架就可以开始调平衡了。附上一部分LL库的底层代码。

首先是串口DMA接收完成中断+空闲中断处理陀螺仪数据,这俩中断组合起来是我最喜欢的处理定时定长数据包的操作,效率高且能避免丢字节的情况

//初始化配置  
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 11);   //陀螺仪一帧11字节
LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)&USART1->RDR);    //外设地址为串口接收数据寄存器
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)uart1_rx_buf);    //内存地址为长度为11字节的数组
LL_DMA_ClearFlag_TC1(DMA1);                   //使能中断前最好清空一下标志位防止误触发
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);   //DMA接收完成中断
LL_USART_EnableDMAReq_RX(USART1);             //使能串口DMA接收请求
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); //使能DMA通道
LL_USART_ClearFlag_IDLE(USART1);              //清除标志位
LL_USART_EnableIT_IDLE(USART1);               //使能串口空闲中断
LL_USART_Enable(USART1);                      //使能串口

当串口空闲时,表示陀螺仪一帧数据发送完毕,这时候判断DMA接收是否完成,如果接收未完成就说明一定丢字节了,这一帧数据就可以放弃掉了,直接重新设置DMA接收长度

//串口中断服务函数代码
if(LL_USART_IsActiveFlag_IDLE(USART1))                 //判断是否为串口空闲中断
{
  if(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_1)>0)   //没接收完,误码
  {
    LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 11);  //让DMA重新接收
  }
  LL_USART_ClearFlag_IDLE(USART1);                     //不管接收成不成功都要清空串口标志位
  LL_USART_ReceiveData8(USART1);                       //清空标志位还要读取一下串口防止异常中断
}

最后是DMA接收完成中断,如果成功触发了这个中断,表示数据长度是正确的,此时还需要稍加判断数据内容即可,由于串口的可靠性已经非常高,所以我就只是确定了下帧头,没有再和校验

//DMA中断服务函数代码
extern unsigned char uart1_rx_buf[];
if(LL_DMA_IsActiveFlag_TC1(DMA1))
  LL_DMA_ClearFlag_TC1(DMA1);
//判断帧头是否符合
if(uart1_rx_buf[0]==0X5A && uart1_rx_buf[1]==0x5A && uart1_rx_buf[2]==0x10)
{
  //结算陀螺仪数据
  atti.roll = (float)(uart1_rx_buf[4]<<8|uart1_rx_buf[5])/100-326.7;
  atti.pitch = (float)(uart1_rx_buf[6]<<8|uart1_rx_buf[7])/100-326.7;
  atti.yaw = (float)(uart1_rx_buf[8]<<8|uart1_rx_buf[9])/100-326.7;
  //修改一下数据格式便于使用
  if(atti.pitch>0)
  {
    atti.pitch = 328.7-atti.pitch;
  }
  else
  {
    atti.pitch = -326.7-atti.pitch;
  }
  if(atti.roll>0)
  {
    atti.roll = 328.7-atti.roll;
  }
  else
  {
    atti.roll = -326.7-atti.roll;
  }
  if(atti.yaw>0)
  {
    atti.yaw = 328.7-atti.yaw;
  }
  else
  {
    atti.yaw = -326.7-atti.yaw;
  }

还有个小插曲记录一下,为了防止电机插口设计反,我预留了正反两种接口,对着插口看哪种对的就焊那个,正因为如此,反而给了我反插的机会,经测试,独轮车配的无刷电机还是比较耐艹的,经历了5分钟的24V反接也只是微微发烫,后来测试一点问题没有。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值