用stc15w4k32移植arduino小贱钟Plotclock
本帖最后由 XTXB 于 2018-2-20 19:02 编辑大伙见过类似的东东吧?最早是老外用arduino做的开源项目,用的是avr芯片,春节闲来无事,移植到STC,供大家一乐。
本人业余电子爱好者,多年前从AVR入坑,得到坛友们的无私奉献,收获许多快乐,多谢了!到现在还是菜鸟一个,代码都是东拼西凑的,多多包涵。
在此特别感谢: 傻孩子,马潮,鸿哥,有名称的**,heicad,还有众多网友,当然更要感谢阿莫,感谢amoBBS!
arduino代码:https://github.com/9a/plotclock/blob/master/plotclock.ino
网友作品视频地址:http://v.youku.com/v_show/id_XODIxNTk4MzA4.html。
左图是STC完工成品,数码管显示时,分,星期,写字时数码管熄灭,右图是网友arduino作品。
STC芯片下载线只需四根,串口无需晶振,又不用复位电路,单面板DIY排版超级简洁方便,这也是我不用AVR芯片DIY的主要原因了。
三个舵机的电源端合在一起,电容躺着不占地方,数码管是单排的,把管脚弯了90°,装在TOP层,哦!数码管装倒了。
题外话,硅胶线(用30#细线)做下载线就是爽:软,耐高温,胶皮多次焊接不熔,拆普通杜邦线的插头焊上,爽得不要不要的。
用SolidWorks画的外壳,部分设计参照网友的外壳,在此感谢了。个人经验,PAL材料壳体厚度1.5mm比较好,强度够用,打印也迅速。
笔座XY坐标与舵机角度转换的数学模型,当初我看arduino程序时只敢照抄,后来画图仔细研究了一下,其实就是初中几何及三角函数而已。
C语言程序实现:------从xy坐标到舵机角度转换函数,有了以上的推导,C实现起来好像也不是那么复杂了。
***********************************************************/
float return_angle(float a, float b, float c) //备用函数,已知ABC三边求AC夹角
{
// cosine rule for angle between c and a
return acos((a * a + c * c - b * b) / (2 * a * c));
}
//固定尺寸OL=L1,OT=L2,TH=L3∠TMO=120°,∠HTO=46.7°(实际测量角度)
void set_XY(double Tx, double Ty) 从xy坐标到舵机角度转换函数,
{
float dx;float dy;float c;float a1;float a2;float Hx;float Hy;
delay_ms(1);//写字速度调节
// calculate triangle between pen, servoLeft and arm joint
// cartesian dx/dy
//左舵机臂长度L1,OT=L2
dx = Tx - O1X;
dy = Ty - O1Y;
// polar lemgth (c) and angle (a1)
c = sqrt(dx * dx + dy * dy); // 笔(Tx,Ty)到左舵机中心点L的距离TL
a1 = atan2(dy, dx); //a1=(Tx,Ty)到左舵机中心点与X轴夹角a1=∠TLC,
a2 = return_angle(L1, L2, c);//a2=LO与LT的夹角∠TLO
write_Ms(1,floor(((a2 + a1 - M_PI) * SERVOFAKTORLEFT) + SERVOLEFTNULL));//驱动左舵机
//左舵机角度∠OLC=∠TLO+∠TLC=a1+a2
//舵机总角度180°(弧度3.14)对应总脉宽2000us,
//角度与脉宽转换比例SERVOFAKTORLEFT=总脉宽2000us/总角度180°=2000/3.14=637
//舵机臂安装起始角度=SERVOLEFTNULL
a2 = return_angle(L2, L1, c);//a2=L2与C的夹角∠OTL
//三叉支点H的坐标=(Hx,Hy)
//L3与Y轴的夹角=a1-a2+46.7°
//46.7°=0.815(OT与HT夹角,机械结构决定的)
//∠MTH=∠0TG+∠OTH+180°=(∠LTH-∠LTO)+∠OTH+180°
Hx = Tx + L3 * cos((a1 - a2 + 0.815) + M_PI);
Hy = Ty + L3 * sin((a1 - a2 + 0.815) + M_PI);
// calculate triangle between pen joint, servoRight and arm joint
dx = Hx - O2X;
dy = Hy - O2Y;
c = sqrt(dx * dx + dy * dy);//C=HR
a1 = atan2(dy, dx);//a1=∠HRC,
a2 = return_angle(L1, 45, c);//a1=∠HRP,HP=45
write_Ms(2,floor(((a1 - a2) * SERVOFAKTORRIGHT) + SERVORIGHTNULL));//驱动右舵机
//右舵机角度∠PRC=∠MRC-∠MRP=a1-a2
}
//
C语言程序实现:------舵机角度与高电平脉宽的转换
舵机脉冲周期20ms0°-180°对应高电平0.5ms-2.5ms相差2000us,角度与脉宽转换比例 SERVOFAKTORLEFT=总脉宽/总角度=2000/3.14=637。
左舵机的驱动函数可以写成write_Ms(1,floor(((a1 + a2 - M_PI) * SERVOFAKTORLEFT) + SERVOLEFTNULL)); (floor是取整函数)
1为左舵机编号,由于舵机安装起始角度无法绝对准确,所以先减M_PI=180°,后加180°=SERVOLEFTNULL=2000作为可调补偿量,当初为这个一减一加困惑了很久。
这是arduino写的驱动函数:servo2.writeMicroseconds(floor(((a1 + a2 - M_PI) * SERVOFAKTORLEFT) + SERVOLEFTNULL));
右舵机初始跟左舵机垂直,可调补偿量SERVORIGHTNULL=1000,就是直接加90°。
由于设定字体的中心纵坐标为0,设定01Y=02Y=-25 笔尖位于蓝色中心线最左到最右,旋转角度为90°,舵机摇臂初始安装时与极限位置(橙色虚线)的夹角45°时最佳。
C语言程序实现:------3个舵机驱动脉冲的产生
整体思路:参照开源程序,占用一个16位定时器,连续输出3个舵机所需的高电平,加上剩下的低电平时间凑够舵机驱动周期20ms。
***********************************************************/
void write_Ms(unsigned char Channel,unsigned int value)//舵机驱动函数,channel=通道,value=高电平脉宽(550-2500)us
{
TR0 = 1;//启动定时器0
PWM_Value=(value*2);//时钟24MHz 定时器12分频 计数2次1us
if(PWM_Value>5000)PWM_Value=5000;//脉冲宽度不大于2.5ms
if(PWM_Value<1200)PWM_Value=1200;//脉冲宽度不小于0.6ms
}
void Timer0_Init(void) //servo定时器初始化@24MHz
{
AUXR &= 0x7F; //定时器时钟12T模式24MHz
TMOD &= 0xF0; //设置定时器模式
TL0=(65536-5000)%256;//虽然后面都要重装,但初始化时还是不要太大为好
TH0=(65536-5000)/256;
TR0 = 1;//启动定时器0
//ET0 = 1;//仅在写字时打开定时器0中断,数码管扫描及读时钟时要关闭中断
}
void timer0(void) interrupt 1 //连续输出3路高电平脉冲,剩下的时间为低电平补足20ms
{
TR0 = 0;//关闭定时器0
switch(order)
{
case 1:
PWM_OUT0=1; //开第0路高电平,
TL0=(-PWM_Value)%256;//(-PWM_Value)=(65536-PWM_Value) 定时时间会更精准
TH0=(-PWM_Value)/256; //赋值第0路舵机高电平时间
break;
case 2:
PWM_OUT0=0;//关第0路高电平,开第1路高电平,
PWM_OUT1=1;
TL0=(-PWM_Value)%256;
TH0=(-PWM_Value)/256; //赋值第1路舵机高电平时间
break;
case 3:
PWM_OUT1=0; //关第1路高电平,开第2路高电平
PWM_OUT2=1;
TL0=(-PWM_Value)%256;
TH0=(-PWM_Value)/256; //赋值第2路舵机高电平时间
break;
case 4:
PWM_OUT2=0; //3路舵机低电平时间=20ms-3路高电平时间
TL0=(25536+PWM_Value+PWM_Value+PWM_Value)%256;
TH0=(25536+PWM_Value+PWM_Value+PWM_Value)/256;
order=0;
break;
}
TR0 = 1;//启动定时器0
order++;
}
C语言程序实现:------直线运动插补(插入许多点逼近直线),实现从A(lastX,lastY)走直线到B(pX,pY),
/************************************************/
void drawTo(float pX, float pY) {
float dx; float dy; float c;
int i;
// dx dy of new point
dx = pX - lastX;//以上次点为坐标原点
dy = pY - lastY;
//path lenght in mm, times 4 equals 4 steps per mm
c = floor(4 * sqrt(dx * dx + dy * dy));
//计算两点之间直线距离并取整CxC=AxA+BxB
if (c < 1) c = 1;
for (i = 0; i <= c; i++) {
// 每次走i/c ,逐点走完距离C
set_XY(lastX + (i * dx / c), lastY + (i * dy / c));
}
lastX = pX;//存储此次位置坐标
lastY = pY;
}
//
C语言程序实现:------圆弧运动插补(插入许多点逼近圆弧),弧的圆心(bx,by),半径radius,起始角度start,结束角度ende
/************************************************/
void bogenGZS(float bx, float by, float radius, int start, int ende, float sqee)
{//圆弧圆心(bx,by),圆弧半径radius,起始角度start,结束角度ende,X轴向比例sqee
float inkr = 0.05;//圆弧插补,逆时针每次+0.05°顺时针是-0.05°
float count = 0;
do {
drawTo(sqee * radius * cos(start + count) + bx,radius * sin(start + count) + by);
//三角函数X=斜边*cosα, Y=斜边*sinα,
count += inkr;//下一点旋转角度inkr
}
while ((start + count) <= ende);//到达角度ende,结束
}
//
C语言程序实现:------有了以上函数,如何写数字?
/************************************************/
case 5: //在中心坐标(bx,by)处写数字5
drawTo(bx + 2 * scale, by + 5 * scale);//走到起始位置
lift(0);//落笔
bogenGZS(bx + 5 * scale, by + 6 * scale, 6 * scale, -2.5, 2, 1);//从5的最下端逆时针画圆弧
drawTo(bx + 5 * scale, by + 20 * scale);//画5的脖子
drawTo(bx + 12 * scale, by + 20 * scale);//画5的顶上一横
lift(1);//抬笔
break;
C语言程序实现:------main流程
******************************************/
void main(void)
{
unsigned char Last_ucTemp4=0;//分钟个位记录
delay_ms(5);
Init_devices();//初始化
//ds3231_write_time();//时钟初始数据写入
uiVoiceCnt=40;//开机短响
delay1s();
while (1)
{
key_service_1_win_4_flash();//按键服务的应用程序
display_service_1_win_6_flash(); //显示的窗口菜单服务程序
delay1s();
if(ucTemp4!=Last_ucTemp4){//如果分有变化,开始写字程序,每分钟写一次
P1|=0x3F;////0B xx11 1111;熄灭数码管
Last_ucTemp4=ucTemp4;//保存当前分钟值
IE2 &=~(1<<2);//关定时器2中断
ET0 = 1;//开定时器0中断
/*lift(0); //落笔 没用白板笔
drawTo(rubberx, rubbery); //停留在笔擦位置,小心撞笔,损坏舵机
delay1s();
lift(2); //抬笔 */
/*lift(1); //落笔
drawTo(0, 25);//装配测试,笔从写字板左边走到右边
delay1s();
drawTo(60, 25);
delay1s(); */
Test_DrawTime();//写时间函数
IE2 |=(1<<2);//开定时器2中断,准备按键扫描,数码管显示,
ET0 = 0;//关定时器0中断,防止干扰
}
}
}
//
C语言程序实现:------编译结果,code=13800 ,好家伙,有十几K!
厉害,我这一假期就是睡觉了 点赞,初中学了SIN,COS基本没用过{:sweat:} 这个必须支持。 牛!!!
真心佩服! 这个好玩。牛! 支持!挺好玩的。 厉害!支持楼主 挺好玩的。但是这钟也太能造了 {:titter:}点赞,初中学了SIN,COS基本没用 {:victory:}{:lol:} 本帖最后由 XTXB 于 2018-2-22 07:55 编辑
新年好!多谢各位的点赞!春节还逛坛子的对电子都是真爱,要不咱们移植个更有意思的。https://github.com/grbl/grbl
工程量可能有点大,好在人家已经铺好了路,咱们只是探索一下,应该只是时间问题,有感兴趣的筒子吗?
我大致看了下雕刻机,写字机,3D打印机的开源程序,基本原理都是读取G码数据,然后控制XYZ。代码也都差不多。
大大的赞一个 厉害,大好的假期时间被我浪费了 不错,很有意思 666,前排围观 不错,楼主加油 不错,赞一个, 楼主DIY能力超强哇 太牛了,必须顶一下! 移植grbl不如Marlin啊 Marlin应用范围广一点 厉害了,这个假期就是吃喝睡玩抓螃蟹 不错,感谢楼主分享。我的3D打印机吃灰好久了,改天也仿一个 XTXB 发表于 2018-2-21 12:08
新年好!多谢各位的点赞!春节还逛坛子的对电子都是真爱,要不咱们移植个更有意思的。https://github.com/g ...
这个已经有某位大神移植到了stm32 上面了, 我比较感兴趣的是 marlin这个 只有很久以前 的一个 不完整的移植版 本帖最后由 XTXB 于 2018-2-24 10:11 编辑
panjun10 发表于 2018-2-23 14:45
这个已经有某位大神移植到了stm32 上面了, 我比较感兴趣的是 marlin这个 只有很久以前 的一个 不完整的 ...
marlin的步进电机驱动的确很牛,打印时加减速的声音听着就舒服,值得学习,正好有台3D打印机,机械方面都是现成的,板子也是现成的,把arduino移植到c,哈哈,更省事了 用笔还是太消耗了。可以改成沙盘写字
https://www.elektor.com/arduino-controlled-sand-clock
本帖最后由 XTXB 于 2018-2-24 10:49 编辑
用沙盘,这都想得到,人才啊,赞!舵机精度很重要,4块5的舵机连个直线都画不直。 就喜欢这种高射炮打蚊子的做法,超贱超牛! 哈哈 厉害,这个给小孩子做一个相对不错。 创意不错 有意思,羡慕你们没事搞点这种创意玩的人,现在我已经变懒了。。。。 收藏,收藏,做个小玩具挺好的 支持一下{:sweat:} 楼主牛B得一塌糊涂,必须赞! 支持一下,谢谢分享 牛逼,这个很不错 mark,备用 厉害了,留个印备用。 好玩,改天做个玩玩 想问下这个机械结构哪买的?看着挺好玩的呀 闲鱼翻身 发表于 2018-6-14 12:02
想问下这个机械结构哪买的?看着挺好玩的呀
我有台3d打印机 不错
厉害了 XTXB 发表于 2018-6-17 15:45
我有台3d打印机
{:titter:} 好吧,只能默默口水下 大神,非常不错!{:lol:} 三角函数......我会....那是不可能的了 伟大数学家高斯说过,数学是科学之王。实际上高深技术最终拼的是数学。 本帖最后由 XTXB 于 2018-6-27 09:55 编辑
HXDZ-AAA 发表于 2018-6-26 10:02
伟大数学家高斯说过,数学是科学之王。实际上高深技术最终拼的是数学。
1999年,在任正非的支持下,华为公司在俄罗斯建立了专门的算法研究所,招聘了数十名全球顶级的数学家,创造性地用非线性数学多维空间逆函数解决了GSM多载波干扰问题。算法研究所突破了移动网络的几个特殊瓶颈,使华为成为全球第一家实现GSM多载波合并的公司,通过软件打通2G、3G和4G网络,使2G、3G、4G产品可以在同一平台上运行,不再需要一个波段一根天线,节省成本,还节省空间,这可能是华为在移动基站领域得以崛起的最重大的突破。 机械臂 也是这个算法 厉害了,亲 不错,很有意思!备用{:lol:} 学习了,感谢楼主分享!~ 帖子移动通知:
原分论坛:8051/STC32【已下线】
目标分论坛:51单片机
移动时间:0小时之后
页:
[1]