本项目,是将一个模拟量A/D转换后用USART输出,用开发板上的芯片转换成RS232电平后定时上传给上位机。同时对最近的学习做一个总结,归纳记录一下从模板项目建立新项目的方法,以及底层代码应用代码分离的框架的建立。
-
设置的流程
设置的流程简述:
复制粘贴新项目 更改.ioc文件名称
设置GPIO管脚和外设功能
设置时钟
设置生成成对的.h和.c文件以及生成hex文件
设置中断
设置调试配置
生成代码
-
软件的框架
设置完成后就进入软件编程阶段。
- 软件框架的大致套路:
新建xxx_app.h和xxx_app.c文件 xxx_app.h内声明功能的初始化函数原型和功能函数原型
xxx_app.c的任务:系统内置的虚函数重新定义、中断回调函数重新定义或桥接、各种功能函数的定义等
main.c内运行各种功能的初始化函数以及调用自定义的功能函数
-
创建一个新项目和配置阶段
1. 复制粘贴新项目
- 打开已经存储在本地的模板项目:


- 在项目管理器里鼠标右键复制之前创建好的模板项目,粘贴为新项目并重命名:



- 项目管理器中模板文件上鼠标右键,删除模板项目,工作区只保留新项目:

2. 更改.ioc文件的名称


3. 设置GPIO管脚
这个项目用到的外设功能是ADC和USART,另外需要有定时器中断来控制定时上传数据。
双击.ioc文件,打开设置视窗:

我的开发板,PA0、PA1、PA2和PA3都已有定义,并接有器件,所以不适合作为ADC的输入。这里选择IN4作为ADC输入,它对应的输入管脚是PA4:

4. 设置ADC参数
全部默认即可。

5. 打开ADC中断

6. 设置定时器


7. 设置USART


这里注意优先级的设定,USART最高,TIM其次,ADC最低。
7. 设置时钟
ADC的输入时钟不得超过14MHz,所以时钟设置这里要设为合适的分频比:


8、生成代码前的设置
选择“生成成对的.h和.c文件”。

设置生成hex文件:
资源管理器右键项目

9. 调试的设置

如果这里已有内容但不是本项目的名称,将其删除,并新建配置

调试器的设置:DAP.cfg是之前创建的模板项目中的文件,参见之前的文章。

10. 生成代码
由于前面选择了“生成成对的.h和.c文件”,系统在生成代码时会对各个功能外设生成独立的文件,可以方便低管理和修改。

-
软件编程阶段
1. 新建应用功能文件
新建xxx_app.h和xxx_app.c文件,用以存放应用层的功能代码和函数:
本项目,是将一个模拟量A/D转换后用USART输出,用开发板上的芯片转换成RS232电平后上传给上位机。用到的功能是A/D转换和USART通信以及定时器中断。所以新建了adc_app.h、adc_app.c和uart_app.h、uart_app.c以及tim_app.h、tim_app.c文件,用来存放相关功能的定义、函数等,方便项目管理和项目移植。

2. adc_app.h
#ifndef __ADC_APP_H
#define __ADC_APP_H
#include "stm32f1xx_hal.h"
void ADC_APP_Init(void); // 声明adc应用初始化函数原型
uint16_t ADC_APP_GetValue(void); // 返回采样值的功能函数原型
#endif
3. adc_app.c
#include "adc_app.h"
#include "stm32f1xx_hal.h" // 根据实际芯片型号调整
extern ADC_HandleTypeDef hadc1; // Cube 生成的句柄
void ADC_APP_Init(void)
{
HAL_ADC_Start(&hadc1); // 软件触发,连续转换
}
uint16_t ADC_APP_GetValue(void) // 获取采样值
{
return HAL_ADC_GetValue(&hadc1);
}
4. uart_app.h
#ifndef __UART_APP_H
#define __UART_APP_H
#include "stm32f1xx_hal.h" // 根据实际芯片型号调整
void UART_APP_Init(void);
void UART_APP_SendVoltage(uint16_t raw12); // 发送格式 "RAW=1234\r\n"
#endif
5. uart_app.c
#include "uart_app.h"
#include <stdio.h>
extern UART_HandleTypeDef huart1;
static uint8_t txBuf[16];
void UART_APP_Init(void)
{
/* Cube 已经初始化 huart1,这里什么都不用做 */
}
void UART_APP_SendVoltage(uint16_t raw12)
{
int len = sprintf((char*)txBuf, "RAW=%04u\r\n", raw12);
HAL_UART_Transmit(&huart1, txBuf, len, HAL_MAX_DELAY);
}
6. tim_app.h
#ifndef __TIM_APP_H
#define __TIM_APP_H
void TIM_APP_Init(void); // main 里调用一次
#endif
7. tim_app.c
#include "tim_app.h"
#include "stm32f1xx_hal.h"
#include "adc_app.h"
#include "uart_app.h"
extern TIM_HandleTypeDef htim2;
void TIM_APP_Init(void)
{
HAL_TIM_Base_Start_IT(&htim2); // 启动中断
}
/* 在 stm32xxxx_it.c 里生成的 TIM2_IRQHandler 会自动调用 HAL_TIM_IRQHandler,
HAL_TIM_IRQHandler 又会调用 HAL_TIM_PeriodElapsedCallback,我们只需重写它 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2)
{
uint16_t v = ADC_APP_GetValue();
UART_APP_SendVoltage(v);
}
}
8. main.c
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "adc_app.h"
#include "tim_app.h"
#include "uart_app.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 2 */
ADC_APP_Init();
UART_APP_Init();
TIM_APP_Init();
/* USER CODE END 2 */
调试阶段
黄色齿轮、甲壳虫。但是发现并没有运行新的程序。
依次点击:

发现这里的.elf文件并不是本项目的。点击“Search Project...”

在弹出窗口选择本项目的.elf文件。点击“确定”。

再次运行调试,在上位机的仿真串口软件中接收到了上传的数据:

-
程序的改进
上面的程序,即使模拟量输入值发生变化,AD转换的数据值也是固定不变的。原因是ADC设置里面没有打开连续转换模式:

设置成连续转换模式后,就可以读取到变化的ADC数据了。

1427

被折叠的 条评论
为什么被折叠?



