实验准备-点灯

本实验环境为 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:自行车码表相关推荐

  1. 基于51单片机自行车码表设计

    [毕设课设]基于51单片机自行车码表设计 ​效果图 Proteus仿真: 功能简介: 文件内容: 程序框架: 网盘链接: ​效果图 更多内容请关注@WENJIE电子科技 ​ 基于51单片机proteu ...

  2. Garmin Edge 1030 Plus GPS 骑行码表今日立减 300 美元

    Prime 会员日已全面生效,甚至山地自行车手和其他骑自行车的人也可以参加 Prime 会员日优惠 .Garmin Edge 1030 Plus自行车电脑在Prime Day的价格降至400美元,如果 ...

  3. 智能可穿戴平台,你更看好谁?

    随着可穿戴设备大潮来袭,众巨头纷纷布局可穿戴.6月,苹果发布了Healthkit平台,谷歌则发布了AndroidWare平台,日前,腾讯(微信)的智能硬件计划曝光.前两者从系统层面出发,都希望自己成为 ...

  4. 从 B 站火到 GitHub,国人开发者又一黑科技面世!

    点击上方"Github爱好者社区",选择星标 回复"资料",获取小编整理的一份资料月石一 发自 凹非寺本文经AI新媒体量子位(ID:QbitAI)授权转载,转载 ...

  5. 《痞子衡嵌入式半月刊》 第 50 期

    痞子衡嵌入式半月刊: 第 50 期 这里分享嵌入式领域有用有趣的项目/工具以及一些热点新闻,农历年分二十四节气,希望在每个交节之日准时发布一期. 本期刊是开源项目(GitHub: JayHeng/pz ...

  6. c语言单片机停车场收费系统,基于51单片机停车场车位引导系统设计

    ?周明彬 曾伊玲 摘要:在很多人流量大的地方,因为车辆集中的情况,所以每次经过停车场时都需要工作人员来指挥车辆,告诉车主停车场那些地方还有空余车位可以泊车.所以很多地方的旧停车场使用的管理方式,是十分 ...

  7. 自制车速记录仪「GitHub 热点速览 v.21.31」

    作者:HelloGitHub-小鱼干 如果你有一辆普通的自行车,那么就可以使用下 X-TRACK 这个项目制作一个自己的测速器,记录你的行驶轨迹还有车速,体验一把硬件发烧友的乐趣.如果你有一个非 ma ...

  8. 基于单片机的压力流量报警器(附代码+仿真+论文)

    基于单片机的压力流量报警器(附代码+仿真+论文) **==完整论文+代码+仿真可关注我在主页私我==** 摘要 关键字 第一章绪论 1.1课题背景及其意义 1.2 国内外的研究状况 1.3本文的主要研 ...

  9. Edge 705试用

    Edge 705是早就听说过的玩意,特别是在环法自行车赛中出尽了风头,那时候在想我要是有一个Edge 705那该多好啊.现在,我终于有了一个Edge 705,是英文版的,不过有已经不错了.只是由于平时 ...

  10. 咕咚为何值1.5亿美元?

    做运动社区和智能硬件产品的咕咚昨日宣布从SIG和软银获得3000千万美金的B轮融资,估值1.5亿美元.咕咚CEO申波表示这笔钱将主要用于研发.运营和人才引进. 之前咕咚曾在今年3月份获得来自深创投和中 ...

最新文章

  1. Delphi 调用webservice接口
  2. Lisp语言: 在Windows下搭建CLisp环境
  3. 注意力机制~Attention Mechanism
  4. [scala-spark]5. 伴生类和伴生对象
  5. 抖音xgorgon04参数
  6. fullcalendar 显示的时间间隔只有四十五分钟_NHR系列智能显示控制仪表RS485通信中应用...
  7. iphone双卡_满屏的iPhone12评测来了,看哪个不重要,买哪个才重要|iphone|国行|iphone12...
  8. 一题多解 —— python ndarray 的 value_counts
  9. 自动化和半自动矢量化提取地物矢量轮廓
  10. 数据库设计文档编写模板
  11. [深度学习] 深度可分离卷积
  12. 如何用java解压文件_如何用Java解压缩文件?
  13. 跑步减肥的正确姿势与方法 不再担心女生跑步腿会变粗
  14. mysql假死_win7系统假死的5种情况和处理方法
  15. 关于Xilinx SDK工具的使用问题求解
  16. 【android学习之十六】——特色功能1:GoogleMap手机地图
  17. 怎么开网店新手怎么开淘宝网店
  18. skywalking和jpa冲突
  19. 基于STM32的无刷电机驱动板 无感/有感制作
  20. 数据预处理 第3篇:数据预处理(使用插补法处理缺失值)

热门文章

  1. 没有互联网,如何本地获取到LoRaWAN的终端数据?
  2. C# 输入一个正整数N,判断N是奇数还是偶数,输出1~N的奇数和或是偶数和,三种不同方法分别实现
  3. 在启动时在Raspberry Pi上运行程序的五种方法
  4. javascript清理IE内存
  5. 儿童汽车拼图游戏 - 儿童游戏拼图2岁-5岁
  6. java 动态定时提醒_java实现定时提醒功能
  7. hdu 5514 2015 icpc 沈阳现场 F Frogs
  8. python猜词游戏演讲ppt_随机猜词游戏
  9. ubantu 安装jekins
  10. IDEA 中定义自己的TODO 并设置快捷键