Lab3:自行车码表
实验准备-点灯
本实验环境为 Mac OS X El Capitan,pd跑 windows 10。
先把下载列表中的软件、驱动都下一遍备用,这时可以喝杯咖啡看看实验攻略 。
强调:东西最好都从官网下,第三方的源在之后有可能掉进各种不知名的坑。
首先安装程序 STM32CubeMX
,打开:
从Help选项卡中的Install New Libraries进入库管理界面,安装对应的库文件。因为在线安装不仅慢而且非常容易断线,所以可以选择左下方的 From Local…
离线安装
或者将库文件压缩包解压到指定路径。
然后就可以新建工程,选择核心板的型号STM32F103C8:
点击Project选项卡中的setting,进入到项目设置:
为了点亮小灯,将PA9设为输出:
点击Project-Generate Code:
如果安装好了 Keil
,就可以用 Keil
打开工程文件了。
这时,如果软件提示你需要安装一个依赖包,那么恭喜你,你多半已经不需要烧录软件,而直接可以用 Keil
download了。如果没有也没关系,我们先来写代码让小灯闪烁。软件已经帮我们自动生成了很多代码,我们只需在 main.c
的main函数中添加如下代码:
while (1)
{HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_9);HAL_Delay(100);
}
点击 中最右方的按钮进行配置,先点击Utilities
选项卡
中的 Settings
按钮:
如果出现了对应的Programming Algorithm,那么你之后就可以直接按 F8
下板了。如果没有也不要慌,我们先把 Reset and Run
打上勾,这样之后下完板后就不需要手动按板子上的 reset
按钮了。
然后,点击 Debug
选项卡
右侧的 Settings
按钮:
如果设备栏里没有报错,说明你已经连上你的板子了。
最后是 Output
选项卡,如果你不能通过 Keil
直接下板,那么就要把 Create HEX File
勾上。
配置完毕,按 F7
编译。如果你可以通过 Keil
直接下板,按 F8
Download。如果不行,那么打开 STM32 ST-LINK Utility
烧录软件:
找到你的hex文件:
点击 连接开发板
按钮,CTRL-E
擦除芯片,CTRL-P
下载程序。结果如下:
连接示意图
ST-LINK接四根线3.3V、GND、SWDIO、SWCLK分别对应STM32板子上的3.3V、GND、DIO、DCLK。此为烧录用的线路。而PA9、PA10为串口通信所用的线路。
串口输出
在 STM32CubeMX
中配置芯片引脚,将PA12、PA11定为输入(接按钮),PA10、PA9分别定为TX、RX(接电脑串口)。
在左侧的配置中,将USART1的模式定为Half-Duplex。
配置完毕,生成代码。接下来在 Keil
中编辑代码。
在 stm32f1xx_hal_conf.h
中解除一些宏定义的注释:
#define HAL_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED
#define HAL_USART_MODULE_ENABLED
在 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);
}int main(void) {...UART_HandleTypeDef UartHandle;UART0_Init(&UartHandle);HAL_UART_Transmit(&UartHandle, (uint8_t*)"Hello, World!\r\n", 16, 500);while (1) {...}
}
HAL_UART_Transmit有4个参数,第一个参数是串口的句柄,第二个参数是一个二进制数组(char*),第三个参数是要发送的数据长度,第四个是发送超时的判定时间。
编译下板,可以看到串口的输出:
检测PA11按钮按下
由于按钮接地,所以,当按钮被按下时,PA11应该可以检测到一个低电平的输入。所以检测到PA11引脚值为1时,即为按钮按下。但在实际实验过程中,需要进行按键去抖动。
// ---------- stm32f1xx_hal_msp.c ----------
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // ---------- main.c ----------
#define MASK 0xFFvoid 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;...while (1) {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);HAL_Delay(5);anti_jitter(&Pin_11_Bitcount,state_11);anti_jitter(&Pin_12_Bitcount,state_12);if (Pin_11_Bitcount != 0 && Pin_11_State == 0) {Pin_11_State = 1;Change_Flag = 1;}if (Pin_11_Bitcount == 0 && Pin_11_State == 1) {Pin_11_State = 0;Change_Flag = 1;}if (Change_Flag == 1) {Change_Flag = 0;if (Pin_11_State == 0)HAL_UART_Transmit(&UartHandle, (uint8_t*)"Pressed!\r\n", 16, 500);}}
}
编译下板,可以看到串口的输出:
PA12下降沿触发中断
PA12引脚的下降沿触发将会触发中断,进入函数EXTI15_10_IRQHandler,此时在函数中调用HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12)表示查看PA12的值,如果符合条件,则触发HAL_GPIO_EXTI_Callback函数。
// ---------- stm32f1xx_it.c ----------
void EXTI15_10_IRQHandler(void) {HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
}// ---------- main.c ----------
int PA12count = 0, PA12flag = 0;void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){if (GPIO_Pin == GPIO_PIN_12){PA12flag = 1;PA12count ++;}else{UNUSED(GPIO_Pin);}
}...int main(void) {...while (1) {...if (PA12flag == 1) {PA12flag = 0;cnt = sprintf(str, "Press 12 %d times\r\n", PA12count);HAL_UART_Transmit(&UartHandle, (uint8_t*)str, cnt, 500); }}
}// 设置中断优先级HAL_NVIC_SetPriority(EXTI15_10_IRQn,0,0);HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
编译下板,可以看到串口的输出:
定时器
定时器中断的实现思路与引脚涉及的中断基本一致。不同的是需要设置中断触发的时间。不同于外部中断,时钟中断是内部触发,所以需要预先设定好触发时间。
同样的,需要覆写中断触发函数TIM3_IRQHandler,而后在其中对时钟进行判断后触发HAL_TIM_PeriodElapsedCallback。并在callback中真正处理逻辑。
// ---------- stm32f1xx_hal_msp.c ----------
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim) {__TIM3_CLK_ENABLE();
}void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htime) {__TIM3_CLK_DISABLE();
}// ---------- main.c ----------
TIM_HandleTypeDef TIM_Handle;
int TIMflag = 0, timer = 0;void TIM3_IRQHandler(void) {HAL_TIM_IRQHandler(&TIM_Handle);
}void TIM_Init() {TIM_Handle.Instance = TIM3;TIM_Handle.Init.Prescaler = 8000;TIM_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;TIM_Handle.Init.Period = 199;HAL_TIM_Base_Init(&TIM_Handle);HAL_TIM_Base_Start_IT(&TIM_Handle);
}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {TIMflag = 1;timer++;
}...int main(void) {...TIM_Init();...while (1) {...if (TIMflag == 1) {TIMflag = 0;cnt = sprintf(str, "clicks: %d \r\n", timer);HAL_UART_Transmit(&UartHandle, (uint8_t*)str, cnt, 500);}}
}// 设置中断优先级HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);HAL_NVIC_EnableIRQ(TIM3_IRQn);
编译下板,可以看到串口的输出:
自行车码表+PA11中断处理(拓展)
自行车码表程序相当于前两步的综合。这里PA11采用了中断模式,方法跟PA12一样。
附上代码:
// ---------- stm32f1xx_it.c ----------
void EXTI15_10_IRQHandler(void) {HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
}// ---------- stm32f1xx_hal_msp.c ---------- GPIO_InitStruct.Pin = GPIO_PIN_11;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_12;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);...void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim) {__TIM3_CLK_ENABLE();
}void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htime) {__TIM3_CLK_DISABLE();
}// ---------- 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);
}#define MASK 0xFFvoid anti_jitter(int *bit, int state) {*bit <<= 1;*bit&= MASK;*bit|=state;
}int mode = 0, PA11flag = 0;
int PA12count = 0;void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {if (GPIO_Pin == GPIO_PIN_11) {PA11flag = 1;mode = 1-mode;} else if (GPIO_Pin == GPIO_PIN_12) {PA12count ++;} else {UNUSED(GPIO_Pin);}
}TIM_HandleTypeDef TIM_Handle;
int TIMflag = 0, timer = 0;void TIM3_IRQHandler(void) {HAL_TIM_IRQHandler(&TIM_Handle);
}void TIM_Init() {TIM_Handle.Instance = TIM3;TIM_Handle.Init.Prescaler = 8000;TIM_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;TIM_Handle.Init.Period = 199;HAL_TIM_Base_Init(&TIM_Handle);HAL_TIM_Base_Start_IT(&TIM_Handle);
}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {TIMflag = 1;timer++;
}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);TIM_Init();HAL_UART_Transmit(&UartHandle, (uint8_t*)"Hello, World!\r\n", 16, 500);while (1) {int cnt;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);HAL_Delay(5);anti_jitter(&Pin_11_Bitcount,state_11);anti_jitter(&Pin_12_Bitcount,state_12);if (PA11flag == 1) {PA11flag = 0;if (mode == 0) {cnt = sprintf(str, "distance mode\r\n");HAL_UART_Transmit(&UartHandle, (uint8_t*)str, cnt, 500);} else {cnt = sprintf(str, "speed mode\r\n");HAL_UART_Transmit(&UartHandle, (uint8_t*)str, cnt, 500); }}if (TIMflag == 1) {TIMflag = 0;if (mode == 0)cnt = sprintf(str, "distance: %f \r\n", (float)PA12count*3.14);elsecnt = sprintf(str, "speed: %f \r\n", (float)PA12count*31.4/timer);HAL_UART_Transmit(&UartHandle, (uint8_t*)str, cnt, 500);}}
}// 设置中断优先级HAL_NVIC_SetPriority(EXTI15_10_IRQn,0,0);HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);HAL_NVIC_EnableIRQ(TIM3_IRQn);
编译下板,可以看到串口的输出:
里程模式
速度模式
下载链接
STM32CubeMX
STM32CubeF1
Patch_CubeFW_F1
KEIL V5.18
ST-LINK驱动
ST-LINK Utility 烧录程序
CH340G USB to TTL驱动
参考资料
第3次实验的指导文档 by 杨凯
STM32F103起步攻略 by 杨凯
Lab3 : 自行车码表 - 不只是实验报告哦
Lab3:自行车码表相关推荐
- 基于51单片机自行车码表设计
[毕设课设]基于51单片机自行车码表设计 效果图 Proteus仿真: 功能简介: 文件内容: 程序框架: 网盘链接: 效果图 更多内容请关注@WENJIE电子科技 基于51单片机proteu ...
- Garmin Edge 1030 Plus GPS 骑行码表今日立减 300 美元
Prime 会员日已全面生效,甚至山地自行车手和其他骑自行车的人也可以参加 Prime 会员日优惠 .Garmin Edge 1030 Plus自行车电脑在Prime Day的价格降至400美元,如果 ...
- 智能可穿戴平台,你更看好谁?
随着可穿戴设备大潮来袭,众巨头纷纷布局可穿戴.6月,苹果发布了Healthkit平台,谷歌则发布了AndroidWare平台,日前,腾讯(微信)的智能硬件计划曝光.前两者从系统层面出发,都希望自己成为 ...
- 从 B 站火到 GitHub,国人开发者又一黑科技面世!
点击上方"Github爱好者社区",选择星标 回复"资料",获取小编整理的一份资料月石一 发自 凹非寺本文经AI新媒体量子位(ID:QbitAI)授权转载,转载 ...
- 《痞子衡嵌入式半月刊》 第 50 期
痞子衡嵌入式半月刊: 第 50 期 这里分享嵌入式领域有用有趣的项目/工具以及一些热点新闻,农历年分二十四节气,希望在每个交节之日准时发布一期. 本期刊是开源项目(GitHub: JayHeng/pz ...
- c语言单片机停车场收费系统,基于51单片机停车场车位引导系统设计
?周明彬 曾伊玲 摘要:在很多人流量大的地方,因为车辆集中的情况,所以每次经过停车场时都需要工作人员来指挥车辆,告诉车主停车场那些地方还有空余车位可以泊车.所以很多地方的旧停车场使用的管理方式,是十分 ...
- 自制车速记录仪「GitHub 热点速览 v.21.31」
作者:HelloGitHub-小鱼干 如果你有一辆普通的自行车,那么就可以使用下 X-TRACK 这个项目制作一个自己的测速器,记录你的行驶轨迹还有车速,体验一把硬件发烧友的乐趣.如果你有一个非 ma ...
- 基于单片机的压力流量报警器(附代码+仿真+论文)
基于单片机的压力流量报警器(附代码+仿真+论文) **==完整论文+代码+仿真可关注我在主页私我==** 摘要 关键字 第一章绪论 1.1课题背景及其意义 1.2 国内外的研究状况 1.3本文的主要研 ...
- Edge 705试用
Edge 705是早就听说过的玩意,特别是在环法自行车赛中出尽了风头,那时候在想我要是有一个Edge 705那该多好啊.现在,我终于有了一个Edge 705,是英文版的,不过有已经不错了.只是由于平时 ...
- 咕咚为何值1.5亿美元?
做运动社区和智能硬件产品的咕咚昨日宣布从SIG和软银获得3000千万美金的B轮融资,估值1.5亿美元.咕咚CEO申波表示这笔钱将主要用于研发.运营和人才引进. 之前咕咚曾在今年3月份获得来自深创投和中 ...
最新文章
- Delphi 调用webservice接口
- Lisp语言: 在Windows下搭建CLisp环境
- 注意力机制~Attention Mechanism
- [scala-spark]5. 伴生类和伴生对象
- 抖音xgorgon04参数
- fullcalendar 显示的时间间隔只有四十五分钟_NHR系列智能显示控制仪表RS485通信中应用...
- iphone双卡_满屏的iPhone12评测来了,看哪个不重要,买哪个才重要|iphone|国行|iphone12...
- 一题多解 —— python ndarray 的 value_counts
- 自动化和半自动矢量化提取地物矢量轮廓
- 数据库设计文档编写模板
- [深度学习] 深度可分离卷积
- 如何用java解压文件_如何用Java解压缩文件?
- 跑步减肥的正确姿势与方法 不再担心女生跑步腿会变粗
- mysql假死_win7系统假死的5种情况和处理方法
- 关于Xilinx SDK工具的使用问题求解
- 【android学习之十六】——特色功能1:GoogleMap手机地图
- 怎么开网店新手怎么开淘宝网店
- skywalking和jpa冲突
- 基于STM32的无刷电机驱动板 无感/有感制作
- 数据预处理 第3篇:数据预处理(使用插补法处理缺失值)