完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>

|
` 本帖最后由 zzq宁静致远 于 2013-11-21 18:37 编辑 8月初以来,在论坛,“朱兆祺带你一步一步学习嵌入式(连载)”(https://bbs.elecfans.com/jishu_357014_1_1.html)以及“朱兆祺教你如何攻破C语言学习、笔试与机试的难点(连载)”(https://bbs.elecfans.com/jishu_354666_1_1.html)得到大家的认可,说明这两个帖子对大家有很大的帮助。这两个帖子都是我接触C语言以来到现在承接单片机、ARM项目的经验总结,我希望通过这两个帖子,各位嵌入式学习者能得到正能量,以最快的方式进步。C语言这个帖子我已经引领网友进入实战项目中,我的C语言功底不是单纯传授书本知识,更重要的是能让各位领略到我这个帖子对你做项目到底有多大的用处。 网友认为,朱兆祺是不是只会编程,只会C语言,只会Linux。OK,朱兆祺趁这个国庆假期,我想此刻很多网友都在游历祖国山河,我就将使用STM32做过的项目小做一下整理,由浅入深、深入浅出,告诉你一个从未接触过STM32的学习者,怎么去做好一个项目,怎样可以代码重用,怎样给项目预留好升级空间。既然是教大家,就使用STM32最强大的那款(STM32F103ZET6、144个引脚),以这个为控制芯片。其实只要你做好模块化编程,控制芯片早已不重要(为什么?后面你会恍然大悟的)。 在进行STM32学习过程中,你们手中最好有一块STM32板子: http://item.taobao.com/item.htm?spm=a1z10.1.w137712-3105488089.8.X83zzd&id=22208871338 购买的时候告诉客服你是看到“朱兆祺STM32项目(硬件设计、软件编程)手记(连载)”购买的,只需要49元,但是每人仅能购买一块。 朱兆祺STM32项目(硬件设计、软件编程)手记(连载)正式开始。 朱兆祺STM32项目手记目录: `
第一节 STM32核心板介绍: https://bbs.elecfans.com/forum.php?mod=redirect&goto=findpost&ptid=385613&pid=2309703&fromuid=222350 第二节 STM32小试牛刀——LED: https://bbs.elecfans.com/forum.php?mod=redirect&goto=findpost&ptid=385613&pid=2309723&fromuid=222350 第三节 UART——调试帮手: https://bbs.elecfans.com/forum.php?mod=redirect&goto=findpost&ptid=385613&pid=2309734&fromuid=222350 第四节 直流电机PID控制: https://bbs.elecfans.com/forum.php?mod=redirect&goto=findpost&ptid=385613&pid=2313310&fromuid=222350 第五节 直流电机PID控制程序: https://bbs.elecfans.com/forum.php?mod=redirect&goto=findpost&ptid=385613&pid=2330272&fromuid=222350 第六节 指针函数在STM32程序中的巧妙应用 https://bbs.elecfans.com/forum.p ... ;amp;fromuid=222350 第七节 PID在智能小车中的应用 https://bbs.elecfans.com/forum.ph ... 2926&fromuid=222350 第八节 关于BOOT问题 https://bbs.elecfans.com/forum.php?mod=redirect&goto=findpost&ptid=385613&pid=2420842&fromuid=222350
|
|
相关推荐
2 条评论
190 个讨论
|
|
|
第七节 PID在智能小车中的应用 应大家要求,来个实例,最好是小车的PID应用。没问题,大家的要求只要是合理我都会答应。自动化有一门课叫运动控制原理,这是自动化的精髓。恰好,我是自动化出身,正宗科班。 /****************************************************************************************** ** 函数名称: CarDriveInit ** 功能描述: 电机驱动初始化 ** 入口参数: 无 ** 出口参数: 无 *******************************************************************************************/ void CarDriveInit(void) { DCMotorA1OUT(); DCMotorA2OUT(); DCMotorA3OUT(); DCMotorA4OUT(); CarStop(); // 初始为停车 GPIO2BreakInit(GPIO2_BREAK_PIN); T161Init(); PIDInit((PID*)&LDCMotorPID); LDCMotorPID.MaxOut = GetPlayData(PAGE7); LDCMotorPID.MinOut = 1; LDCMotorPID.Kp = LDCMOTOR_KP; LDCMotorPID.Ki = LDCMOTOR_KI; LDCMotorPID.Kd = LDCMOTOR_KD; PIDInit((PID*)&RDCMotorPID); RDCMotorPID.MaxOut = GetPlayData(PAGE8); RDCMotorPID.MinOut = 1; RDCMotorPID.Kp = RDCMOTOR_KP; RDCMotorPID.Ki = RDCMOTOR_KI; RDCMotorPID.Kd = RDCMOTOR_KD; } /****************************************************************************************** ** 函数名称: CarAngle ** 功能描述: 小车转固定的角度(定轮方式) ** 入口参数: angle--角度 dir--方向 (1--左转,2--右转) fun--在等待过程中要处理的事件,回调形式完成 ** 出口参数: 无 *******************************************************************************************/ void CarAngle(uint32 angle, uint8 dir, uint8 (*fun)(void)) { uint32 AngleCount = 0; // 需要的角度对应的脉冲数 // AngleCount = 2*PI*LENGHT*angle*CIRCLE_COUNT/(360*CARTWHEEL_GIRTH); // AngleCount = PI*LENGHT*angle*CIRCLE_COUNT/(180*CARTWHEEL_GIRTH); AngleCount = 6.2 * angle - GetPlayData(PAGE9); if (1 == dir){ // 左转 ,对右轮进行计数 CarLStop(); RDCMotorPulseCount = 0; CarRDrive(295,1); while (RDCMotorPulseCount < AngleCount){ if (NULL != fun){ if (fun()) { break; } } }// 等待行走完毕 CarStop(); } else if (2 == dir) { // 右转,对左轮进行计数 CarRStop(); LDCMotorPulseCount = 0; CarLDrive(295,1); while (LDCMotorPulseCount < AngleCount){ if (NULL != fun){ if (fun()) { break; } } }// 等待行走完毕 CarStop(); } } /****************************************************************************************** ** 函数名称: CarBackAngle ** 功能描述: 小车转固定的角度(后退方式) ** 入口参数: angle--角度 dir--方向 (1--左转,2--右转) fun--在等待过程中要处理的事件,回调形式完成 ** 出口参数: 无 *******************************************************************************************/ void CarBackAngle(uint32 angle, uint8 dir, uint8 (*fun)(void)) { uint32 AngleCount = 0; // 需要的角度对应的脉冲数 // AngleCount = 2*PI*LENGHT*angle*CIRCLE_COUNT/(360*CARTWHEEL_GIRTH); // AngleCount = PI*LENGHT*angle*CIRCLE_COUNT/(180*CARTWHEEL_GIRTH); AngleCount = 6.2 * angle - GetPlayData(PAGE11); if (1 == dir){ // 左转 ,对右轮进行计数 CarRStop(); LDCMotorPulseCount = 0; CarLDrive(295,2); while (LDCMotorPulseCount < AngleCount){ if (NULL != fun){ if (fun()) { break; } } }// 等待行走完毕 CarStop(); } else if (2 == dir) { // 右转,对左轮进行计数 CarLStop(); RDCMotorPulseCount = 0; CarRDrive(295,2); while (RDCMotorPulseCount < AngleCount) { if (NULL != fun){ if (fun()) { break; } } }// 等待行走完毕 CarStop(); } } /****************************************************************************************** ** 函数名称: CarMidAngle ** 功能描述: 小车转固定的角度(中心轴方式) ** 入口参数: angle--角度 dir--方向 (1--左转,2--右转) fun--在等待过程中要处理的事件,回调形式完成 ** 出口参数: 无 *******************************************************************************************/ void CarMidAngle(uint32 angle, uint8 dir, uint8 (*fun)(void)) { uint32 AngleCount = 0; // 需要的角度对应的脉冲数 // AngleCount = 2*PI*LENGHT*angle*CIRCLE_COUNT/(360*CARTWHEEL_GIRTH); // AngleCount = PI*LENGHT*angle*CIRCLE_COUNT/(180*CARTWHEEL_GIRTH); AngleCount = 3.1 * angle - GetPlayData(PAGE10); if (1 == dir){ // RDCMotorPulseCount = 0; LDCMotorPulseCount = 0; CarLDrive(295,2); // 左轮反转 CarRDrive(295,1); // 右轮正转 while ((RDCMotorPulseCount < AngleCount)&&(LDCMotorPulseCount < AngleCount)) { // 等待行走完毕 if (NULL != fun){ if (fun()) { break; } } } CarStop(); } else if (2 == dir) { // RDCMotorPulseCount = 0; LDCMotorPulseCount = 0; CarLDrive(295,1); // 左轮反转 CarRDrive(295,2); // 右轮正转 while ((RDCMotorPulseCount < AngleCount)&&(LDCMotorPulseCount < AngleCount)) { // 等待行走完毕 if (NULL != fun){ if (fun()) { break; } } } CarStop(); } } /****************************************************************************************** ** 函数名称: CarArcAngle ** 功能描述: 小车转固定的角度(弧线模式) ** 入口参数: angle--角度 dir--方向 (1--左转,2--右转) fun--在等待过程中要处理的事件,回调形式完成 ** 出口参数: 无 *******************************************************************************************/ void CarArcAngle(uint32 angle, uint8 dir, uint8 (*fun)(void)) { uint32 LAngleCount = 0; // 需要的角度对应的脉冲数 uint32 RAngleCount = 0; // 需要的角度对应的脉冲数 if (1 == dir){ // 左转 ,对右轮进行计数 LAngleCount = PI*(GetPlayData(PAGE12))*angle*CIRCLE_COUNT/(180*(CARTWHEEL_GIRTH)) - GetPlayData(PAGE16); RAngleCount = PI*(LENGHT+GetPlayData(PAGE12))*angle*CIRCLE_COUNT/(180*(CARTWHEEL_GIRTH)) - GetPlayData(PAGE14); CarStop(); RDCMotorPulseCount = 0; LDCMotorPulseCount = 0; CarLDrive(GetPlayData(PAGE15),1); // 左轮慢 CarRDrive(GetPlayData(PAGE13),1); // 右轮快 while ((RDCMotorPulseCount < RAngleCount)||(LDCMotorPulseCount < LAngleCount)) { if (RDCMotorPulseCount >= RAngleCount){ CarRStop(); } if (LDCMotorPulseCount >= LAngleCount){ CarLStop(); } if (NULL != fun){ if (fun()) { break; } } }// 等待行走完毕 CarStop(); } else if (2 == dir) { // 右转,对左轮进行计数 RAngleCount = PI*(GetPlayData(PAGE12))*angle*CIRCLE_COUNT/(180*(CARTWHEEL_GIRTH)) - GetPlayData(PAGE16); LAngleCount = PI*(LENGHT+GetPlayData(PAGE12))*angle*CIRCLE_COUNT/(180*(CARTWHEEL_GIRTH))- GetPlayData(PAGE14); CarStop(); RDCMotorPulseCount = 0; LDCMotorPulseCount = 0; CarLDrive(GetPlayData(PAGE13),1); // 左轮快 CarRDrive(GetPlayData(PAGE15),1); // 右轮慢 while ((RDCMotorPulseCount < RAngleCount)||(LDCMotorPulseCount < LAngleCount)) { if (RDCMotorPulseCount >= RAngleCount){ CarRStop(); } if (LDCMotorPulseCount >= LAngleCount){ CarLStop(); } if (NULL != fun){ if (fun()) { break; } } }// 等待行走完毕 CarStop(); } } /****************************************************************************************** ** 函数名称: CarLineLength ** 功能描述: 小车走指定的距离 ** 入口参数: length--行走长度 单位(mm) dir--方向 (1--前进,2--后退) fun--在等待过程中要处理的事件,回调形式完成 ** 出口参数: 无 *******************************************************************************************/ void CarLineLength (uint32 length, uint8 dir, uint8 (*fun)(void)) { uint32 LineCount = 0; // 需要的距离对应的脉冲数 //AngleCount = length*CIRCLE_COUNT/(CARTWHEEL_GIRTH); LineCount = 2.1 * length - GetPlayData(PAGE28); LDCMotorPulseCount = 0; RDCMotorPulseCount = 0; CarRDrive(GetPlayData(PAGE18),dir); CarLDrive(GetPlayData(PAGE17),dir); // 等待行走完毕 while ((RDCMotorPulseCount < LineCount)||(LDCMotorPulseCount < LineCount)) { if (RDCMotorPulseCount >= LineCount){ CarRStop(); } if (LDCMotorPulseCount >= LineCount){ CarLStop(); } if (NULL != fun){ if (fun()) { break; } } } CarStop(); } |
|
|
|
|
|
|
|
|
本帖最后由 zzq宁静致远 于 2013-11-5 14:59 编辑
第七节 关于BOOT问题 是不是有网友问我,BOOT是干什么使用的。在明志电子科技工作室设计的STM32F103ZET6核心板中,有BOOT0和BOOT1两个引脚从VCC和GND中进行搭配使用,其中BOOT1即为PB2。详细图片描述查看附件。 当BOOT0连接低电平时,不管BOOT1连接的是高电平还是低电平,启动模式为从片内Flash启动、即为用户闪存启动,这是正常的启动方式。BOOT0 = 0,BOOT1 = 0or1。 当BOOT0连接的是高电平时,BOOT1连接的是低电平,此时启动模式为从系统存储器中启动,这个方式由厂家决定。BOOT0 = 1, BOOT0 = 0。 当BOOT0连接的是高电平时,BOOT1连接的是高电平,此时的启动模式为内置的SRAM启动,稍微了解系统的“行家”都知道,这个地方厂家内置了一段Bootloader,也就是我们所说的ISP程序。这对于调试。BOOT0 = 1, BOOT0 = 1。这种情况请慎重使用,特别是初学者。 在一般情况下我们烧写程序使用STM32时,是这种情况:BOOT0 = 0,BOOT1 = 0or1。所以使用明志电子科技工作室设计的STM32F103ZET6核心板的时候,我们需要使用两个跳冒将BOOT0和BOOT1接GND。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
你正在撰写讨论
如果你是对讨论或其他讨论精选点评或询问,请使用“评论”功能。
STM32F405驱动DS1302时钟模块,输出时间错乱该怎么排查?
2810 浏览 2 评论
stm32f405rgt6驱动DS1302ZN出现时间错乱问题
2420 浏览 1 评论
stm32用fsmc读取ad7606采集数据,数据不变,只有开发版复位才更新数据
2288 浏览 0 评论
2404 浏览 1 评论
1643 浏览 1 评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-2 13:47 , Processed in 1.004717 second(s), Total 85, Slave 75 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖
10147