每节课都是一个项目 手把手用STM32打造联网气象站-7-诚不欺我,用TIM, GPIO, USART三板斧干项目(挖坑篇)

终于,我们把STM32的入门三板斧的武功讲完了。有了这三板斧,我们就可以完成一些基本的项目了。终于熬出头了,从这一节开始,我们就用这三板斧,来玩不同的项目了。

当然。我们的项目不仅仅是玩,每一个项目都至少包含下面元素:

1.高耦合低内聚,便于移植,便于重用;

2. 不仅仅是好玩,而且有用,在其他项目中常常用得到;

敬请收藏,关注,从下面开始,带你做项目带你飞!

目录

1. 实战项目1-开发一个番茄钟

1.1项目背景

1.2 需求分析

1.3 项目开发

 1.3.1 修改定时器中断间隔时间

 1.3.2 修改main.c中的代码,设置倒计时时间为25分钟;

1.3.3  控制led闪烁时间及闪烁频率

1.3.4 实现beep蜂鸣一次的响停间隔及蜂鸣频率

1.3.5 在main.c中,检查SysTickFlags时间标志,根据分钟标志,实现分钟显示

2. 实战项目2-改进番茄时钟

2.1项目需求

2.2需求分析

2.3项目开发步骤

2.3.1 移植串口,实现串口环回测试

2.3.2 串口命令解析,串口指令测试

2.3.2 增设串口指令,修改单个番茄时长

2.3.3 通过串口获取完成的番茄个数

2.3.4 通过串口指令,暂停、开始番茄时钟

3. 实战项目3-摩斯密码翻译器

3.1项目需求

3.2需求分析

3.3开发步骤

3.3.1摩尔斯电码基本原理

3.3.2 从gethub查找摩尔斯电码相关代码,对其功能进行测试

3.3.3 分析代码结构,修改GPIO引脚,实现beep发送莫尔斯码。

3.3.4 实现按标准时间间隔发送

3.3.5 将全部符号与摩尔斯电码相对应。



1. 实战项目1-开发一个番茄钟

1.1项目背景

现代人很容易被各种琐事打扰,一会儿一个微信,一会儿一个电话,一会儿一条手机弹窗,让人们很难真正安静下来,从事写作或者学习。

为了解决这个问题,我们利用手边的STM32开发板,开发一款番茄时钟,具体功能如下:

1. 开机后,自动倒计时25分钟;

2. 倒计时时间,例如:剩余24分钟时,闪烁24下,剩余1分钟时,闪烁1次。闪烁频率为100ms亮,200ms熄灭;

3. 到达倒计时时间后,蜂鸣器会“滴滴滴滴”想起,蜂鸣器想起频率为100ms开900ms关,蜂鸣器响25S后,自动停止;

就是这样简单的一个项目,接下来我们进行需求分析,看看如何快速实现这个项目。

1.2 需求分析

根据前面的三板斧,我们可以知道,这个项目需要这样实现:

1.开启定时器中断,定时器中断间隔设置为10ms;

2. 设置SystemCounter全局结构体变量,用来计算秒和分钟;

3. 采用前面用过的led_check来控制亮灭时间和闪烁次数;

4. 开发类似led_check的函数,来控制蜂鸣器的频率和次数;

5. 从下面这个项目的源码入手修改

每节课都是一个项目 手把手用STM32打造联网气象站-5-STM32基础三件套-采用TIM定时器,实现无阻塞LED任意占空比和次数闪烁_可志嵌入式的博客-CSDN博客

1.3 项目开发

 1.3.1 修改定时器中断间隔时间

每节课都是一个项目 手把手用STM32打造联网气象站-4-STM32基础三件套-TIM定时器初始化_可志嵌入式的博客-CSDN博客

根据这一节中2.2的内容,我们知道,设置10ms中断间隔,我们可以把Period设置为10000-1; Prescaler保持不变。

 1.3.2 修改main.c中的代码,设置倒计时时间为25分钟;

       宏定义实现倒计时时间的设置,便于led闪烁、蜂鸣器亮灭次数统一

 

设置好宏定义后,用宏定义作为参数,判定倒计时时间

1.3.3  控制led闪烁时间及闪烁频率

1)在led_check.h,通过修改控制闪烁时间的宏定义,控制闪烁频率为亮100ms,灭200ms。

2)在main.c中,配置set_led_config实现闪烁次数的要求

 

1.3.4 实现beep蜂鸣一次的响停间隔及蜂鸣频率

        1)开发beep_check函数控制蜂鸣器的频率和次数

        2)开发set_beep_config函数,用以初始化蜂鸣器的频率和次数。

参考:

每节课都是一个项目 手把手用STM32打造联网气象站-5-STM32基础三件套-采用TIM定时器,实现无阻塞LED任意占空比和次数闪烁_可志嵌入式的博客-CSDN博客

思路一样,只是注意bsp_beep.h中,beep开启、关闭与led对应的电平不同。最后要注意在main.c大循环中添加beep_check用以控制蜂鸣器的频率和次数

1.3.5 在main.c中,检查SysTickFlags时间标志,根据分钟标志,实现分钟显示

        1)在控制时间的结构体中增加TimeFlag,用以设置单次运行模式,当时间超过25分钟后,通过对标号4,设置TimeFlag为1,便不再执行番茄番茄时钟程序

        2)检查SysTickFlags时间标志,实现分钟显示

        3)通过对时间标志 按位取反 再与原值位于运算,达到清除时间标志,而不影响其他位的数值。

        4)位与位或等运算可参考:

位与&, 位或| ,位异或 ^ 总结 - Lucky& - 博客园 (cnblogs.com)https://www.cnblogs.com/xiaokang01/p/9651366.html

纸上得来终觉浅,绝知此事要躬行!

马上下载测试代码,看看效果。

测试代码链接

https://download.csdn.net/download/book_drabit/86150743

2. 实战项目2-改进番茄时钟

2.1项目需求

前面的番茄时钟虽然不错,但是还存在两个问题:

1. 没有输入设备,时间始终是固定死的;

2. 没有累计数据,不知道一天到底完成了几个番茄;

3.没有暂停功能,无法在需要时对番茄时钟进行暂停

为了解决这个问题,我们接下来就开发改进版本的番茄时钟;

2.2需求分析

为了实现这个需求,我们需要

1. 在前面工程基础上,移植串口,方便通过串口,设定番茄钟的时间,启动番茄钟,暂停番茄钟。这样,我们就需要开发一下串口解析命令。另外,为了是的代码更加便于维护,我们不仅仅通过串口控制,而且可以通过串口,查询番茄钟的软件版本信息和硬件版本信息;

2. 在前面的SystemConter的结构体全局变量中,我们需要增加一个累计番茄的变量,这样每次完成一个番茄,通过串口输出出来。同时也可以通过串口命令,查询共计完成了几个番茄。

2.3项目开发步骤

在前一节的基础上,我们需要:

2.3.1 移植串口,实现串口环回测试

解析串口代码结构,理解其串口协议,并通过串口发送指令进行验证。

1)带有串口协议的代码如下:

串口收发指令代码,实现用指令获取硬件版本号与软件版本号-C文档类资源-CSDN下载

对此串口代码进行移植:

首先,将此代码目录下的串口c文件和h文件文件复制到番茄时钟文件夹usart里面;

其次,在keil工程内将鼠标右键放在USER目录上,右键选择Manage Project Items,在USER目录下添加bsp_usart.c文件,

最后,点击魔法棒->C/C++选项卡->include paths将bsp_usart.h文件目录包含进去

测试。移植好后进行串口环回测试,向单片机发送字符,查看单片机返回的字符是否一致。

 向单片机发送GHJ,单片机返回GHJ,发送与返回的字符一致,串口移植成功。

串口环回代码如下:

番茄时钟通过移植增设串口通信,并通过串口环回测试-C文档类资源-CSDN下载

2.3.2 串口命令解析,串口指令测试

完成环回之后,我们已经确定串口有效,串口能够接收数据,并且发送出来,在此基础上,我们进一步开发串口命令解析功能。

第一步:it.c中接收完整的串口命令并存入缓存

第二步:缓存中解析命令;

第三步:测试结果,验证功能;

1)在串口中断函数中缓存完整的串口命令

 在串口中断服务函数中,urt_recv_tmp数组用于缓存完整的串口命令

在这里要注意一下,CurrentRxStep接收8个字节后,CurrentPoint才会累加

2)解析缓存中的串口指令

首先,代码开始执行时, PrePoint和CurrentPoint初始值都是0。当串口收到8个字节后,CurrentPoint增加1,这时PrePoint!=CurrentPoint,会进行命令复制,将串口收到的命令复制到UARTGetComm[ ]数组内。然后PrePoint自增,使得PrePoint和CurrentPoint再次相等。

其次,不断刷新串口状态,没有收到命令时,uart_status处在URT_IDLE状态,不停的break返回。当串口收到了正确命令后,UrtOrderReceiveFinish这个标志会被设置为SET,这时,uart_status进入URT_RX状态,进行串口命令解析。

 最后,通过ReadCom函数提取指令的内容,根据指令的内容执行不同的操作。

         其中指令A0 B1 02 00 00 00 00 00为获取固件版本信息。在测试的时候可以进行使用。

 至此,串口命令解析到此结束。下面通过测试验证其功能。

3)测试以验证功能

通过串口助手向单片机发送指令A0 B1 02 00 00 00 00 00,查看返回的固件版本是否一致。

对应代码如下:

https://download.csdn.net/download/book_drabit/86247414

2.3.2 增设串口指令,修改单个番茄时长

在完成对串口指令的解析后,增加通过串口指令修改单个番茄时长。

第一步:定义全局变量,通过在程序内修改全局变量,控制番茄时长

第二步:增设串口指令,通过指令修改控制番茄时长的全局变量

第三步:测试结果,验证功能

1)增设全局变量,控制番茄时长

本节上部分开发番茄时钟时以讲过,可参考本节上部分内容。

2)在ReadCom函数中增设修改番茄时长的指令

首先,将指令第四位,即UARTGETCom[3]的值赋给TomatoTime全局变量。当修改时长后,番茄时钟重新开始计时,设立TomatoRestartFlag标志位用于控制番茄时钟是否清零用于计数的参数。

其次,在主函数中,根据TomatoRestartFlag判断是否复位番茄时钟计数参数。 根据TomatoTime的值对番茄时长进行控制。

至此,通过串口修改番茄时长功能完成开发完成,下一步进行测试。

3)串口修改番茄时间功能测试

 首先,在stm32f10x_it.c中修改定制器中断1分钟时长为6秒,缩短测试时间。

其次,通过串口助手向单片机发送16进制指令A0 B1 03 02 00 00 00 00,根据延时进行判断功能是否正常

经测试代码功能符合要求。

串口修改番茄时长代码如下:

(48条消息) 通过串口控制单个番茄时钟时长-C文档类资源-CSDN文库

2.3.3 通过串口获取完成的番茄个数

需求:1.一个番茄结束后,自动发送共完成的番茄个数。2.通过串口指令获取完成的番茄个数。

        第一步:设置全局变量,用于记录共完成的番茄个数

        第二步:当完成一个番茄后,通过串口将记录番茄个数的全局变量数值发给上位机

        第三步:增设串口指令,当单片机收到指令后,通过串口将记录番茄个数的全局变量数值发给上位机

        第四步:测试以验证功能

1)通过全局变量记录番茄个数

首先,在bsp_TimeBase.c定义一个全局变量(全局变量会自动初始化为0)

其次,在 bsp_TimeBase.h中用extern进行引用

最后,在主函数中包含此头文件即可使用此全局变量

 2)当完成一个番茄后,FinishTomatoNum会自动增加 1 ,并通过串口将数值上报

首先,当番茄时间到,全局变量自动增加1

其次,通过串口将全局变量FinishTomatoNum进行打印

 再次,通过设置TomatoTimeEndFlag标志位为1;while(1)循环便不在执行此番茄始终程序。

最后,对功能进行测试,通过发送指令,查看单片机的返回值是否与完成次数一致

测试结果,功能正常

3)增加串口指令 0xA0 B1 04 返回完成的番茄次数全局变量值到串口助手

首先,筛选串口数据开头为0xA0 B1 04的指令

其次,设置DealFlag=0;表示完成指令。设置uart_status = URT_IDLE;以便进行下一次数据接收

 4)测试功能,验证功能的正确性

首先,向单片机发送开头为0xA0 B1 04的8个字节数据,

其次,对比单片机返回值与实际结果是否一致

 单片机返回值与实际结果一致,测试通过。

代码如下:

(48条消息) 通过串口获取完成的番茄个数-C文档类资源-CSDN文库

2.3.4 通过串口指令,暂停、开始番茄时钟

需求:1.暂停时,番茄时钟停止计时,秒不再增加,时间停止

           2.番茄时间结束后。按暂停功能,番茄时钟重新计时    

第一步,增设暂停标志位

第二步,定时器中断检测暂停标志位,停止更新秒变化标志位,达到暂停时间功能

第三步,增设串口暂停指令,控制暂停标志位。

第四步,测试验证功能正确性

1)增设暂停标志位

 首先,在bsp_TimBase.h文件中  Tomato结构体中增设TomatTimePauseFlag

 其次,在bsp_TimBase.c文件中定义一个Tomato类型的结构体变量

最后,在bsp_TimBase.h文件extern引用此结构体变量,这样其他文件中的函数可以通过include bsp_TimBase.h文件,进而引用此结构体全局变量。

 2)定时器中断检测暂停标志位,停止更新秒变化标志位,达到暂停时间功能

首先,进入定时器中断函数,检测TomatClock.TomatTimePauseFlag不为0后,SystemTimer.second停止自增,进而SystemTimer.second == 6 条件不满足,分钟标志位停止更新。

 其次,在main.c中,tomat_contrl_led_beep函数,检测不到分钟标志位,便停止更新led和beep蜂鸣器。

 3)增设串口暂停指令,控制暂停标志位。

首先,筛选出串口数据表头为0xA0 B1 04的指令

其次,判断若指令UARTGetComm[3] == 1,则设置标志位TomatTimePauseFlag为1,前面说过,若TomatTimePauseFlag为1,则定时器中断函数中,SystemTimer.second停止自增。

再次,判断若指令UARTGetComm[3] == 0,则设置标志位TomatTimePauseFlag为0,这样定时器中断函数中,SystemTimer.second自增,并再次判断,如果番茄时钟时间截至标志位TomatClock.TomatTimeEndFlag 为1,设置番茄时钟重新启动。

最后,设置DealFlag=0,表明指令处理结束,设置uart_status = URT_IDLE,继续进行下一次串口消息接收。

4) 测试验证功能正确性

即通过串口单片机向单片机发指令 0xA0 B1 04 01 00 00 00 00  番茄时钟暂停计时。发指令 0xA0 B1 04 00 00 00 00 00  番茄时钟继续计时

 测试通过,功能符合要求。

 至此,完成番茄时钟所有需求

1.通过串口指令修改番茄时钟计时时间

2.通过串口指令查看共完成的番茄个数。

3.当一个番茄时间完成后,会自动通过串口发送共完成的番茄个数

4.通过串口指令,暂停、开始番茄时钟

对应代码如下

(48条消息) 实现番茄时钟暂停功能,设置番茄时钟结构体替代取代控制番茄时钟的全局变量,详情见博客-C文档类资源-CSDN文库

3. 实战项目3-摩斯密码翻译器

3.1项目需求

电影中,常常可以看到很多关键情报,都是通过摩斯密码来传递的。然而,翻译摩斯密码并不容易。

摩斯密码采用一系列的点和线,来实现信息的表达和传递。

3.2需求分析

说老实话,真的用代码,从头开始,翻译摩斯密码,还是非常有挑战的。所以这一节,我们将介绍另外一种常用方法:从github找相关思路。

github是程序员的乐园,极客的世界,在github上面,说不定已经有摩斯密码翻译器了,我们只需要把它下载下来,再移植到我们的代码中,即可完成项目功能。

说干就干,我们再github上面,能够找到类似的项目。

3.3开发步骤

第一步,了解摩尔斯电码基本原理

第二步,从gethub查找摩尔斯电码相关代码,对其功能进行测试

第三步,分析代码结构,增加功能,实现用蜂鸣器将消息以摩尔斯电码的方式滴答发送出去

3.3.1摩尔斯电码基本原理

首先,摩尔斯电码通过点(.)和横杠(-)的组合代表不同的字符,字符构成单词,转变为人可以理解的词汇。

        's', "..."                             'o', "---"                            's', "..."  

 其次,将字符转化为摩尔斯电码,更有利于通过简单的滴答声及延时将信息发送出去。由于不同字符由不同的摩尔斯电码组成,不同的摩尔斯电码对应不同时长的滴答声和滴答声间隔。字符便被区分开来。

********************************************************************************************
*    摩尔斯电码时间间隔包括五种:
*
*        1、点( · )                   :1 (读 “滴” dit ,时间占据1t )
*        2、划(—)                     :111 (读 “嗒” dah ,时间占据3t )
*        3、字符内部的停顿(在点和划之间):0 (时间占据1t )
*        4、字符间停顿                   :000 ( 时间占据3t )
*        5、单词间的停顿                 :0000000 ( 时间占据7t )
*
**********************************************************************************************

具体请参考一次看懂摩斯电码的密码 - 知乎 (zhihu.com)

3.3.2 从gethub查找摩尔斯电码相关代码,对其功能进行测试

首先,从gethub查找相关代码,github是极客的世界,有大量的优质开源项目。要学会使用github。github的使用大致分为账号注册、创建github仓库、git工具的安装三大步,此处不再赘述,详细使用请参考

还不会使用 GitHub ? GitHub 教程来了!万字图文详解 - 知乎 (zhihu.com)

从gethub下载的摩尔斯电码代码如下:

(40条消息) 摩尔斯电码,实现将字符转为摩尔斯电码的主体功能,能将摩尔斯电码通过串口上位机进行显示-C文档类资源-CSDN文库

其次,将代码下载到单片机进行验证,其能实现基本的字符转为摩尔斯电码功能,将摩尔斯电码通过串口进行显示。将摩尔斯电码以led闪烁的形式发送出去

3.3.3 分析代码结构,修改GPIO引脚,实现beep发送莫尔斯码。

第一步,分析代码结构

第二步,修改GPIO引脚,实现beep发送莫尔斯码。

1)进入主函数,查看其对摩尔斯电码函数的调用,分别查看(1)和(2)两个标签对应的函数。

首先, morse_init函数实现对摩尔斯电码GPIO引脚的初始化,后续可以通过GPIO对应的蜂鸣器将信号以声音的方式发送出去。

 其次,不定长函数morse_printf实现两个功能(1):将摩尔斯电码通过串口打印显示。(2)将摩尔斯电码通过GPIO外接的led输送给外界。

可见,此摩尔斯电码只是将字母与摩尔斯电码对应起来,部分符号如  ? ( )等符号没有完善。

可见,摩尔斯电码发送时间间隔没有严格按照摩尔斯电码要求进行等待。

最后,对代码进行完善,增加摩尔斯电码对其他字符的支持,增加对莫尔斯码发送时间间隔的支持。在下一节讲述

不定长函数可参考下文:

void morse_printf(char *format, ...) { } 为不定长函数,其对输入参数的个数没有要求。不定长函数的基本调用方式为:

void my_printf(const char *format, ...)
va_list arg;  // va_list是一个宏,是指向不定长参数列表的指针
va_start(arg, format);   //初始化arg,将format后第一个地址赋值给arg
va_arg(arg, int);    //得arg指向参数的值,同时使arg指向下一个参数
vsnprintf((char *)pStr, 100, format, ap); 
va_end(arg); 
  //va_end 在有些实现中可能会把arg改成无效值,
//这里, 是把arg指针指向了 NULL,避   免出现野指针

 具体可参考(40条消息) C语言 函数不定长参数 - C语言零基础入门教程_猿说编程的博客-CSDN博客_c++不定长参数 

2)对功能进行完善,实现用蜂鸣器将消息以摩尔斯电码的方式滴答滴答发送出去

 首先,将led改为beep蜂鸣器

在Morse_TX.h修改宏定义,注意,由于电路不同,beep高电平为打开。

其次,在Morse_TX.c修改GPIO引脚为PA8

 经测试,beep蜂鸣器正常闪烁。

3.3.4 实现按标准时间间隔发送

第一步,修改beep发送时间间隔,实现按标准时间间隔发送

第二步,增设对其他符号摩尔斯码的支持

第三步,测试以验证功能

  1. ( · ):1 (读 “滴” dit ,时间占据1t )
  2. 横杠(—):111 (读 “嗒” dah ,时间占据3t )
  3. 字符内部的停顿(在点和划之间):0 (时间占据1t )
  4. 字符间停顿:000 ( 时间占据3t )
  5. 单词间的停顿:0000000 ( 时间占据7t )

        在Morse_TX.c中做如下操作,

1),设定基准等待时间、设定基准时间倍乘系数,这样代码看起来更清晰明了

2),在morse_printf函数内部,设置点、横杠、字符内部、字符间、单词间的时间停顿

3),修改完成后需对其功能进行验证,打开纸飞机串口助手,打开时间戳功能,对时间进行验证

 单个时间戳是90ms,.... 共用时10个时间戳,共900ms,红框中时间间隔正确。以此类推对所有时间间隔进行验证,均符合要求。

3.3.5 将全部符号与摩尔斯电码相对应。

 首先,在const tp_morse_index  st_morse[ ]最下方添加 “ / ” 用于摩尔斯电码单词之间的间隔。

其次,在morse_printf中添加switch语句,使输出字符与摩尔斯码一一对应。

最后,对以上功能进行验证,观察蜂鸣器与串口显示

经验证,功能正常。

代码如下:

(48条消息) 摩尔斯电码,实现将摩尔斯电码通过串口进行打印,通过蜂鸣器进行发送,具体详情见博客-C文档类资源-CSDN文库

这一段对话请每一个程序员或者有志于编程的人牢记:

老板:这个代码不是开源的吗?怎么需要这么久?开源的还需要你自己写吗?

程序员:*……&*……&*……&¥……%¥564@#¥@

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很高兴与您进行对话。根据您的要求,我可以为您提供一个用于STM32的带有PID的GA25-370驱动代码,用TIM8产生PWM信号。以下是示例代码: ```c #include "stm32f4xx.h" // PID控制器的参数 #define KP 0.5 #define KI 0.5 #define KD 0.5 // PID控制器的变量 float error = 0; float integral = 0; float derivative = 0; float last_error = 0; float setpoint = 0; // 期望值 float output = 0; // PID计算的输出值 // 电机控制相关的常量 #define PWM_PERIOD (255) // PWM信号的周期 #define PWM_DIV (64) // PWM信号的分频 #define MOTOR_DIR_PIN (GPIO_Pin_0) // 电机方向引脚 #define MOTOR_DIR_PORT (GPIOC) // 电机方向引脚所在端口 // 电机控制相关的变量 uint8_t duty_cycle = 0; // PWM信号的占空比 GPIO_InitTypeDef gpio_init_struct; // GPIO初始化结构体 /** * @brief 初始化TIM8和PWM信号输出引脚 */ void TIM8_PWM_Init(void) { // 初始化TIM8 TIM_TimeBaseInitTypeDef tim_init_struct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE); tim_init_struct.TIM_Period = PWM_PERIOD; // 设置分频系数,得到的TIM时钟为2.25MHz(72MHz/64) tim_init_struct.TIM_Prescaler = PWM_DIV - 1; tim_init_struct.TIM_ClockDivision = 0; tim_init_struct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM8, &tim_init_struct); // 初始化PWM模式通道1 TIM_OCInitTypeDef tim_oc_init_struct; TIM_OCStructInit(&tim_oc_init_struct); tim_oc_init_struct.TIM_OCMode = TIM_OCMode_PWM1; tim_oc_init_struct.TIM_OutputState = TIM_OutputState_Enable; tim_oc_init_struct.TIM_Pulse = 0; TIM_OC1Init(TIM8, &tim_oc_init_struct); TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable); // 设置PWM信号输出引脚 gpio_init_struct.GPIO_Pin = GPIO_Pin_6; gpio_init_struct.GPIO_Mode = GPIO_Mode_AF; gpio_init_struct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &gpio_init_struct); GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM8); // 启动TIM8 TIM_Cmd(TIM8, ENABLE); } /** * @brief 初始化电机方向控制引脚 */ void Motor_Init(void) { // 配置GPIO引脚 gpio_init_struct.GPIO_Pin = MOTOR_DIR_PIN; gpio_init_struct.GPIO_Mode = GPIO_Mode_OUT; gpio_init_struct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(MOTOR_DIR_PORT, &gpio_init_struct); // 默认初始方向为正转 GPIO_SetBits(MOTOR_DIR_PORT, MOTOR_DIR_PIN); } /** * @brief 控制电机方向 * @param[in] direction 控制方向 0表示反转,1表示正转 */ void Motor_Direction(int direction) { if (direction == 0) { GPIO_ResetBits(MOTOR_DIR_PORT, MOTOR_DIR_PIN); } else { GPIO_SetBits(MOTOR_DIR_PORT, MOTOR_DIR_PIN); } } /** * @brief 控制电机转速 * @param[in] speed 控制转速 -255表示最慢,255表示最快 */ void Motor_SetSpeed(int speed) { // 控制方向 if (speed < 0) { Motor_Direction(0); speed = -speed; } else { Motor_Direction(1); } // 控制PWM信号 duty_cycle = speed; TIM_SetCompare1(TIM8, duty_cycle); } /** * @brief PID控制器 * @param[in] input 输入值,通常为传感器采集的反馈信号 * @return 输出值,通常为控制器输出的控制信号 */ float PID_Controller(float input) { // 计算误差 error = setpoint - input; // 计算积分项 integral += error; // 计算微分项 derivative = error - last_error; last_error = error; // 计算PID输出 output = KP * error + KI * integral + KD * derivative; return output; } /** * @brief 主函数 */ int main(void) { Motor_Init(); // 初始化电机控制相关的引脚 TIM8_PWM_Init(); // 初始化TIM8和PWM信号输出引脚 while (1) { // TODO: 读取传感器采集的反馈信号 // 计算PID控制器的输出 output = PID_Controller(input); // 控制电机转速 Motor_SetSpeed(output); // TODO: 延时一段时间 } } ``` 以上代码是一个简单的PID控制器示例,用于控制一个GA25-370电机的转速。您需要根据实际情况进行修改,比如读取传感器的反馈信号、设置期望值等。同时,请注意安全性问题,不要让电机转速过快或过慢,以免引起危险。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值