本篇文章由 VeriMake 旧版论坛中备份出的原帖的 Markdown 源码生成
原帖标题为:一辆有脸蛋的小铲车
原帖网址为:https://verimake.com/topics/270 (旧版论坛网址,已失效)
原帖作者为:余归(旧版论坛 id = 169,注册于 2021-09-30 00:07:32)
原帖由作者初次发表于 2021-10-01 00:07:31,最后编辑于 2021-10-01 00:07:31(编辑时间可能不准确)
截至 2021-12-18 14:27:30 备份数据库时,原帖已获得 397 次浏览、4 个点赞、0 条回复
如何使用CH549去做一个有脸蛋的小铲车呢
特别注明:此次作品由VeriMake大家族出品!
先不多直接说上图!!!

是不是有些激动了呢!不要着急待我慢慢给大家介绍下去。
首先是产品的3D建模部分
组成这个小车的打印零件有9个也都是一些很简单的零件组成的。

模型的爆炸视图,直观的展示所有的零件。
结构介绍:大臂和头部的动力来源是SG90舵机,车体移动的动力来源是N20减速电机。
零件之间相互连接大多数使用的是M2的自攻螺丝,少部分使用M3的螺丝与螺母连接,这种连接的办法降低了零件的打印难度。使一些精度相对低一些的打印机也可以打印出零件。
其次是产品的电路部分

主控采用的是:沁恒科技的CH549单片机
- 增强型E8051内核CPU,速度比标准MCS51快8-15倍,特有XRAM数据快速复制指令;
- 内置60KB Code Flash、1KB Data Flash和3KB BootLoader,支持USB和串口ISP;
- 内置2KB XRAM和内部256B RAM;
- 内嵌USB控制器和USB收发器,支持USB2.0全速和低速主机或设备,支持DMA;
- 内嵌Type-C CC控制器,支持USB PD;
- 提供支持 FAT12/FAT16/FAT32 文件系统的 U 盘文件级子程序库,实现读写 U 盘文件;
- 提供3组定时器/计数器,支持3路引脚信号捕捉和8路PWM输出;
- 提供4个全双工异步串口;
- 提供1个SPI通信接口,支持主/从模式;
- 提供与GPIO复用的16通道12位ADC模数转换器;
- 提供16通道电容触摸按键;
- 内置时钟和PLL,也可支持外部晶振。
- 封装:SOP16、QFN28、LQFP48
- 由于这个芯片的内核和传统的8051内核一致,这一点对一致使用STC系列单片机的同学就很有好了,这意味着软件程序方面大部分可以直接的Ctrl+C Ctrl+V
此次的PCB上面会插入这个小板子,这是由我们VeriMake工作室设计的一块基于CH549单片机的最小系统板。
遥控采用的是:沁恒科技的CH9140蓝牙模块
这个模块支持蓝牙BLE4.2,串口波特率最大1Mbps,最最最大的特点我认为是此模块设计的非常的迷你小巧,很适合做一些体积相对较小的电子制作。
电机驱动采用的是:TC1508
此驱动的峰值电流为2.5A,内部是双通道的功率MOS全桥,供给给N20电机使用绰绰有余。
电源管理使用的是TP4056
这个芯片的峰值充电电流为1A,通过调节PROG引脚的对地电阻即可修改充电电流
遵循公式:Rporg=1200/Ibat;
升压电路采用的是SX1308
这是一款Boost升压芯片,配置3号引脚的上拉和下拉电阻即可修改输出端电压
遵循公式Vout=Vref*(1+R上拉/R下拉);Vref为反馈电压0.6V
此电源用于提供舵机,单片机和OLED屏幕的电源。
降压稳压芯片:此芯片用于给蓝牙模块提供一个3.3V的电源。
电路方面的坑!!!
舵机频繁工作的时候电流很大,升压部分输出电压被拉低,这会导致单片机电源被拉低复位,解决的办法是:在单片机的电源上面并联一个大电容,并且增加一个电流流向向内的二极管。
最后是产品的软件程序部分
程序方面的设置当然还是和STC51单片机一样的Keil,相信大部分同学都不会陌生。
外设端口定义
sbit djA1=P2^4;
sbit djA2=P2^2;
sbit djB1=P3^4;
sbit djB2=P3^5;//电机端口定义
sbit Arm=P0^4;//大臂舵机定义
sbit Head=P1^6;//头部舵机定义
sbit ledr=P1^4;//左转LED
sbit ledl=P1^5;//右转LED
由于控制两个电机的正反转则需要四个GPIO去控制
Arm和Head是大臂和头部两个舵机的信号端
ledr和ledl是车头下方的左边灯和右边灯
除此之外还有串口的端口没有定义,使用的是P26和P27端口
所定义的函数:
void Get_Value(void);//得到电池电压
void Device_Init();//外设初始化
void timer_init(void);//100us定时器初始化
void display();//显示表情和电量
void move_contrl();//车身移动控制
void led_contrl();//LED控制
外设初始化:初始化所有的软硬件外设 (初始化控制电机的GPIO电平,串口,定时器,OLED显示屏)
void Device_Init()//外设初始化
{
djA1=0;
djA2=0;
djB1=1;
djB2=1;//电机初始状态赋值
CH549UART1Init();//串口1初始化
ADC_ExInit(3);//初始化ADC采集
mDelaymS(20);
OLED_Init(); //初始化OLED
mDelaymS(20);
OLED_Clear();
mDelaymS(20);
}
得到ADC端口电压:读取电池电压,进行电量检测
void Get_Value()
{
ADC_ChSelect(CH0);//选择通道
ADC_StartSample();//开启采样
while((ADC_CTRL&bADC_IF) == 0); //查询等待标志置位
ADC_CTRL = bADC_IF;//清除标志
Value=ADC_DAT;//电压转换,转换为当前检测管脚的电压的10倍(即3.7v显示37)
}
选择通道CH0是指P10端口,P10端口挂在了电池的VCC上面,得到数据之后将数据赋值给变量,供后续使用。
定时器初始化函数:(初始化定时器0为50us定时器,用来模拟软件PWM给舵机使用)
void timer_init()//定时器初始化
{
TMOD=0x01;
TH0=(65535-100)/256;
TL0=(65535-100)%256;
TR0=ET0=EA=1;
}
显示函数:(显示表情和当前电池剩余电量)
void display()
{
static char k,time;
if(dat<10&&dat==0)time++;
if(time>=15&&dat==0) //当为静止状态
{
Get_Value();//查看电池电量
OLED_DrawLine((128-Value)/2,128-((128-Value)/2),7,dat);//电量条显示
time=0;
k=!k;
}
if(dat==0&&k==0) OLED_DrawBMP(0,0,128,50,eyes_open,dat); //睁眼
if(dat==0&&k==1) OLED_DrawBMP(0,0,128,50,eyes_close,dat); //闭眼
if(dat==1) OLED_DrawBMP(0,0,128,50,forward,dat); //前进
if(dat==2) OLED_DrawBMP(0,0,128,50,back_off,dat); //后退
if(dat==3) OLED_DrawBMP(0,0,128,50,turn_left,dat); //左转
if(dat==4) OLED_DrawBMP(0,0,128,50,turn_right,dat); //右转
}
这里的dat就是通过上位机(手机遥控APP)发送来的数据

标题提到表情这边的前进后退等等,对应显示的就是这边的表情,具体的实现使用专门的取模软件,导入图片设置好取模方式就可以直接用OLED显示器显示了。

想要复刻的小伙伴们可以自行导入像素密度为128*64的BMP格式的图片进去修改小车的表情
定时器0的中断服务函数:
void timer_zd() interrupt 1
{
static int PWM;
PWM++;
TH0=(65535-100)/256;
TL0=(65535-100)%256;//50us定时器
if(PWM>=400)PWM=0; //周期控制
if(PWM>=move1) Arm=0; //大臂控制
else Arm=1;
if(PWM>=move2) Head=0;//头部控制
else Head=1;
}
模拟的PWM周期为20Ms,占空比通过move1和move2两个变量分别控制两个舵机,占空比的范围是0到12.5%。
Main函数:
void main()
{
CfgFsys(); //CH549时钟选择配置
ledl=ledr=1;//led全部关闭
Device_Init();//外设初始化
move1=32;
move2=18;
timer_init();//定时器初始化
while(1)
{
display();//显示函数
move_contrl();//车身移动控制
led_contrl();
}
}
程序流程:时钟配置→外设初始化→while循环
循环内:显示函数显示表情,同时串口等待外部上位机发送信息,根据发送信息做出不同的反应。