STM32F103实现自行车里程计
STM32F103实现自行车里程计
器材准备
- STM32F103板子一个
- 杜邦线、面包线、面包板若干
- ST-LINK V2 一个(烧录程序)
- USB-TTL 一个(做串口输出测试)
- 按钮两个
- Win电脑一台(建议不要在mac下开发,实在太难受了)
连接
- usb to ttl 和 stm32开发板连接图
[id](#Table 1)
USB | STM32 |
---|---|
3.3V | 3.3V |
GND | GND |
TXD | A10 |
RXD | A9 |
- stm32和st-link直接按照对应的接口相连即可
环境搭建
软件安装
- Keil UVision 5
- STM32 ST-LINK Unity
- STM32 CubeMX
- STM32 ST-LINK所需要的驱动
- USB-TTL所以需要的驱动 CH341SER for Win(这个视你的器件不同而定)
- PUTTY(windows下查看串口)
软件使用
开始之前记得一定要先将驱动都安装好!
STM32 CubeMX
进入STM32 CubeMX之后就可以使用了,我们选择STM32F103 - LQFP48 - 64Flash - 20RAM(老师提供的板子)进行配置。
STM32F103只是一块板子,我们先需要对板子进行简单的设计,比如哪个引脚做输入,哪个引脚做输出等等,直接使用STM32实现自行车里程计可能会出现一些完全想不到的错误,实现一些简单的功能对所用的器件进行简单测试(譬如是不是能正常工作的)。
由于我们使用的板子是STM32F103,直接使用CubeMX会去下载这个库,但是它自己下载速度超级慢,这里可以使用浏览器下载到 1.3.0版本的库,然后使用CubeMX下一个补丁就可以了,速度会快很多。
然后Project->Settings修改工程设置,将Toolchain修改成MDK-ARM V5(否则默认是EWARM),这样我们之后才可以使用Keil进行项目管理。最后,Project -> Generate Code即可生成代码。
Keil UVision 5
使用上面的工具 设置好引脚之后就可以开始写代码了,直接在CubeMX中选择OpenProject就可以打开工程文件。
将ST-LINK与STM32对应的借口连起来,然后调好设置:Flash->Configure Flash Tools->Debug->Settings查看连接是否正确,连接成功将如下图所示。
使用Keil生成HEX文件然后利用ST-LINK烧录进STM32中,需要在Flash->Configure Flash Tools->Output中勾选Create HEX File选项,如下图所示。其实不使用ST-LINK Unity,直接使用Keil也是能够烧录下板的,但是需要使用Patch Installer下载一个Algorithm,下载速度特别慢,因此这里还是使用生成HEX文件再利用ST-LINK Unity进行烧录的方法。
- Flash->Configure->Utilities在Add Output File to Group选定Application/MDK-ARM,不然在目录下找不到对应的HEX文件。
- Flash->Configure->Utilities->Settings选定Reset and Run,在STM32上使用的是ISP编程,烧录时要对芯片中Flash原有的数据全部抹除,烧进自己的数据,然后重新启动,bootloader起来后会跑对应的指令(在使用Keil下板时有用)。
- 注意!每次重新打开Keil一定要记得将上面的流程全部都走一遍,不然就会出错,真是想吐槽这个IDE,一旦重启原来的设定就都不见了。
STM32 ST-LINK Unity
- 将ST-LINK撤下,换上USB-TTL并接入PC(记得提前装好驱动),打开ST-LINK,导入一个HEX文件,如果像上面使用Keil建好的工程,则HEX文件在Project name/MDK-ARM/Project name下
- 点击connect to the target,如果报错了说明是你的线路没接对或者驱动没装好
- 点击Target->Erase Chip将芯片内Flash的数据全部擦除
- 点击Target->Program & Verify,烧录数据,完成后烧录成功,芯片会执行对应的功能
元器件测试以及简单逻辑代码框架
闪烁小灯
芯片引脚设置(PA9作为输出)
线路连接
先使用STM32的3.3V输出检验二极管的方向,然后如下图所示小灯一个脚接GND,一个脚接A9,这样当A9输出高电平时小灯就会亮了。
小灯在成功点亮之后说明杜邦线和小灯都是正常的(否则小灯可能就是坏的,或者线是坏的,只是极有可能的,我们连续测了三个小灯全是坏的,开始还以为是烧录少错了,查了好久,换成蜂鸣器做测试的时候居然响了。。。)。然后就可以使用面包板给小灯串联一个按钮,检测按钮和面包板的好坏,盒子里的器材中,我们又检测出一个按钮是坏的(按与不按小灯都会有信号)。
- 代码
我们之前对A9进行了设置,这个在工程中的main.c函数内有具体的体现。
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct; //定义初始化结构
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_9; //对端口9进行初始化
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
}
自己写代码实现小灯闪烁
while(1) {
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_9); //转换A9的输出状态
HAL_Delay(1000);
}
- 总结
至此,我们实现使用STM32开发板完成了闪烁小灯的任务,通过以上的步骤,可以将所有的坏的元器件过滤掉,避免之后的bug大串联到焦头烂额,并且整体跑通了STM32开发的流程,之后的开发按照这个模板来就可以了。
串口通信
- 芯片引脚设置
将PA9,PA10设置为串口通信用的TX和RX(对应接法已经在上面的表格中表达出来了),注意要在CubeMX中将USART1设置为半双工(Cortex-M3的单线程半双工模式),将PA12和PA11设为Input,我们将两个按钮分别接到这两个引脚和GND,这样芯片可以根据两个引脚的输入进行交互。
线路连接
原谅我这鬼畜的波浪线,如图所示,直接将两个USB口全部接到电脑上,就可以不用重复的插拔插拔了(共用了电源线)。A11,A12分别接上两个button用来监测按钮的状态,将A11,A12内部设置为上拉到输入模式(接一个上拉电阻),在main()函数内进行循环检测,并在其中一个按钮按下时,输出两个按钮的状态信息。
按键已经去抖动,上方是按键状态后得到的输出。
- 代码
main.c中进行修改
/*-------------------------------main.c------------------------------------*/
//....
void UART0_Init(UART_HandleTypeDef* UartHandle){
UartHandle->Instance = USART1;
UartHandle->Init.BaudRate = 9600;
UartHandle->Init.WordLength = UART_WORDLENGTH_8B;
UartHandle->Init.StopBits = UART_STOPBITS_1;
UartHandle->Init.Parity = UART_PARITY_NONE;
UartHandle->Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle->Init.Mode = UART_MODE_TX_RX;
HAL_UART_Init(UartHandle); //初始化UART
}
//根据输入对给定的端口进行初始化,设置波特率等等
#define MASK 0xFF
//给按钮去抖动检测的长度(8bit)
void anti_jitter(int *bit, int state)
{
*bit <<= 1;
*bit&= MASK;
*bit|=state;
}
//按钮不只是在开合的时候会有抖动,不按下的时候线路都会时断时续,所以去抖动一定要加上
int main(void)
{
//...
char str[30];
int Pin_11_Bitcount = 0,Pin_12_Bitcount=0;
int Pin_11_State=0,Pin_12_State=0;
int Change_Flag=1;
UART_HandleTypeDef UartHandle;
UART0_Init(&UartHandle);
//设置变量,并对UART0进行初始化
HAL_UART_Transmit(&UartHandle, (uint8_t*)"Hello, World!\r\n", 16, 500);
//在Reset之后立刻向串口输出信息Hello, World! 这里记得要加入\r\n,否则输出的全是糊的
while(1)
{
int count;
GPIO_PinState state_11;
GPIO_PinState state_12;
state_11 = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11);
state_12 = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12);
//读取11、12的端口的状态,但是直接使用这些状态会有抖动的情况
HAL_Delay(5);
//延迟五秒用来延长读取状态的间隔,用来去抖动
anti_jitter(&Pin_11_Bitcount,state_11);
anti_jitter(&Pin_12_Bitcount,state_12);
//对两个端口去抖动,state_11,state_12是当下的
木偶人的感情: 您好,老哥,真的看到您设计的里程计,感觉又看到了希望,因为我最近也在做一个里程计,老哥写的真的好细心。感谢老哥,老哥能不能分享一下您的源码。因为我最近在也做这个,真的很麻烦老哥。万分感谢780900694@qq.com