文章背景:

作为一个STM32的新手小白,在学习并调试完单个模块代码后,接下来遇到的问题必然是如何将多个模块的代码合并到一个工程里。但是网上搜寻了很多资料,都没有对这块内容进行详细的解说。在这里笔者做一个总结,方便其他新手小白在跨过这道坎上能节省一些时间成本。


项目特征:

笔者入门时使用的是正点原子的战舰V3板STM32F103ZET6的教程。正点原子给的代码是用KEIL5文件打开的。所有的实验都整理的非常整齐。他会分为大致五类(USER HARDWARE SYSTEM CORE FWLib)。其中很多代码都是对应STM32F103ZET6芯片的代码源。我们真正要编写的只有USER里的main.c文件以及HARDWARE文件里的各类模块代码源。

以LMT70温度模块为例:

HADEWARE文件里主要都是各类外设模块的代码源。这里以温度传感器LMT70为例。该传感器模块是通过ADC通道来上传热敏电阻阻值的模拟信号。对应的接口为AOUT或AO或OUT。在战舰V3板STM32F103ZET6中ADC通道与GPIO口的对应关系如下表所示。

再看HAREWARE里的adc.c文件:

 #include "adc.h"#include "delay.h"//初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3
void  Adc_Init(void)
{   ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_ADC1 , ENABLE );   //使能ADC1通道时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M//PA1->PB1 作为模拟通道输入引脚                         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        //模拟输入引脚GPIO_Init(GPIOB, &GPIO_InitStructure);  ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;    //ADC工作模式:ADC1和ADC2工作在独立模式ADC_InitStructure.ADC_ScanConvMode = DISABLE;    //模数转换工作在单通道模式ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  //模数转换工作在单次转换模式ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐ADC_InitStructure.ADC_NbrOfChannel = 1;  //顺序进行规则转换的ADC通道的数目ADC_Init(ADC1, &ADC_InitStructure);  //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   ADC_Cmd(ADC1, ENABLE);  //使能指定的ADC1ADC_ResetCalibration(ADC1);  //使能复位校准  while(ADC_GetResetCalibrationStatus(ADC1));   //等待复位校准结束ADC_StartCalibration(ADC1);    //开启AD校准while(ADC_GetCalibrationStatus(ADC1));  //等待校准结束
//  ADC_SoftwareStartConvCmd(ADC1, ENABLE);     //使能指定的ADC1的软件转换启动功能
}
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)
{//设置指定ADC的规则组通道,一个序列,采样时间ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );  //ADC1,ADC通道,采样时间为239.5周期                   ADC_SoftwareStartConvCmd(ADC1, ENABLE);     //使能指定的ADC1的软件转换启动功能    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
}u16 Get_Adc_Average(u8 ch,u8 times)
{u32 temp_val=0;u8 t;for(t=0;t<times;t++){temp_val+=Get_Adc(ch);delay_ms(5);}return temp_val/times;
}

代码中有adc_init()初始化函数以及相应u16 Get_Adc(u8 ch)数据读取函数以及平均值处理u16 Get_Adc_Average(u8 ch,u8 times)函数。在初始化中。adc_init()初始化函数有如下图所示对GPIO引脚的定义。正点原子中默认为将引脚定义为PA1(对应通道为–通道1)。由于PA1引脚被其他模块占用,我们在这里改为PB1(对应通道为–通道9)

adc_init()初始化函数的其他部分是对ADC1的配置,有兴趣改为ADC2的可以自行尝试。

主函数:

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "adc.h"int main(void){    u16 adcx;float temp;float tem;delay_init();             //延时函数初始化    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级uart_init(115200);     //串口初始化为115200Adc_Init();               //ADC初始化while(1){adcx=Get_Adc_Average(ADC_Channel_9,10);temp=(float)adcx*(3.3/4096)*1000;tem = (-0.0000084515)*temp*temp+(-0.176928)*temp+204.393-0.5;printf("\r\nADC电压为:%.2f",tem);delay_ms(10); }}

主函数主要是先对各个变量进行定义。接下来是对延迟函数、优先级、串口、以及ADC通道等进行初始化。最后在while1中对温度数据进行处理与现实。
可以看到代码adcx=Get_Adc_Average(ADC_Channel_9,10);是对通道9的引用,与之间通道9的初始化相互对应。


配置流程:

通过上述的讲解,我们较为清楚的了解代码的结构。接下来详细介绍一下代码的配置流程:
a.先选择相应的芯片代码源(需要在类似魔法棒的地方选择相应的芯片)。

b.对HAREWARE文件进行其他模块代码的放入(本实验放入了源代码adc.c).下图为放入方式:
(1)右击项目的任意文件,选择如下图的Manage Project Items…

(2)点开后在里面选择HARDWARE文件,在右下角Add Files…中选择对应.c文件放入。

(3)之前的放入仅是将文件简单的导入进项目中,并没有配置文件的路径。我们需对文件路径进行配置:
以下图为例:先点击左上角的魔法棒,在打开的窗口中选择C/C++。在里面找到Include Paths并点击后面的…。在出来的窗口中点击右上角的方框进行文件路径的添加。

通过以上步骤,我们即可将其他地方的HARDWARE文件导入到该项目中进行编辑。从而为代码的合并打下基础。


合并代码:

接下来是对代码的合并讲解。本文章以陀螺仪传感器IMU901与温度传感器LMT70为例进行合并。下图为两个模块的HARDWARE文件。由于陀螺仪的代码相对温度复杂,若将温度项目导入到陀螺仪项目中,会相对于陀螺仪项目导入到温度项目简单。

a.新建一个文件,将陀螺仪文件重新复制一个到新建文件内。将温度中ADC代码源复制到该文件中的HARDWARE里。

b.打开项目,在目录中将adc.c文件导入

c.魔法棒中导入adc.c文件的路径。与上述路径导入方式相同。接下来点击右上角第二或第三个按键进行项目编译(第二个是对项目简单编译,第三个是对整个项目重新编译)。如下图所示adc.c文件前面会多出来"+"。说明导入成功。

d.主函数合并,如下代码为陀螺仪的主函数:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "usart2.h"
#include "imu901.h"int main(void)
{uint32_t times = 0;uint8_t ch;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVIC中断分组2:2位抢占优先级,2位响应优先级//sys_stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */delay_init();                         /* 延时初始化 */LED_Init();                             /* 初始化LED */uart_init(115200);                     /* 串口初始化为115200 */usart2_init(115200);imu901_init();                          /* IMU901模块初始 */while (1){if (imu901_uart_receive(&ch, 1))  /*!< 获取串口fifo一个字节 */{if (imu901_unpack(ch))          /*!< 解析出有效数据包 */{if (rxPacket.startByte2 == UP_BYTE2)          /*!< 主动上传的数据包 */{atkpParsing(&rxPacket);}}}else{delay_ms(1);times++;//if (times % 300  == 0) printf("loading....");    /* 提示系统正在运行 */if (times % 1000 == 0)                  /*!< 1秒打印一次数据 */{printf("\r\n");printf("姿态角[XYZ]:    %-6.1f     %-6.1f     %-6.1f   (°)\r\n", attitude.roll, attitude.pitch, attitude.yaw);printf("加速度[XYZ]:    %-6.3f     %-6.3f     %-6.3f   (g)\r\n", gyroAccData.faccG[0], gyroAccData.faccG[1], gyroAccData.faccG[2]);printf("角速度[XYZ]:    %-6.1f     %-6.1f     %-6.1f   (°/s)\r\n", gyroAccData.fgyroD[0], gyroAccData.fgyroD[1], gyroAccData.fgyroD[2]);}}}
}

和并之后的主函数:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "usart2.h"
#include "imu901.h"
#include "adc.h"int main(void)
{  u16 adcx;float temp;float tem;uint32_t times = 0;uint8_t ch;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVIC中断分组2:2位抢占优先级,2位响应优先级//sys_stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */delay_init();                         /* 延时初始化 */LED_Init();                             /* 初始化LED */uart_init(115200);                     /* 串口初始化为115200 */usart2_init(115200);imu901_init();                          /* IMU901模块初始 */Adc_Init();             //ADC初始while (1){if (imu901_uart_receive(&ch, 1))   /*!< 获取串口fifo一个字节 */{if (imu901_unpack(ch))          /*!< 解析出有效数据包 */{if (rxPacket.startByte2 == UP_BYTE2)          /*!< 主动上传的数据包 */{atkpParsing(&rxPacket);}}}else{delay_ms(1);times++;//if (times % 300  == 0) printf("loading....");    /* 提示系统正在运行 */if (times % 1000 == 0)                  /*!< 1秒打印一次数据 */{printf("\r\n");printf("姿态角[XYZ]:    %-6.1f     %-6.1f     %-6.1f   (°)\r\n", attitude.roll, attitude.pitch, attitude.yaw);printf("加速度[XYZ]:    %-6.3f     %-6.3f     %-6.3f   (g)\r\n", gyroAccData.faccG[0], gyroAccData.faccG[1], gyroAccData.faccG[2]);printf("角速度[XYZ]:    %-6.1f     %-6.1f     %-6.1f   (°/s)\r\n", gyroAccData.fgyroD[0], gyroAccData.fgyroD[1], gyroAccData.fgyroD[2]);adcx=Get_Adc_Average(ADC_Channel_9,10);temp=(float)adcx*(3.3/4096)*1000;tem = (-0.0000084515)*temp*temp+(-0.176928)*temp+204.393-0.5;printf("\r\nADC电压为:%.2f",tem);}}}
}

最终烧录代码后通过xcom数据调试成功

总结:

其实只要深刻了解了项目文件的各个部分的作用,合并起来还是非常容易的。就是对源文件进行扩充与路径配置,最后在主函数比较合理的罗列出来即可。
但是各个代码也有各个代码自身的问题。可能在合并中会遇到各种奇怪的问题。像我这个陀螺仪在前面数据接收部分写上printf(“1”);整个xcom就都是1。数据也出不来。但是注释掉之后数据也能正常显示,不过进过调整之后最终数据还是能正常显示出来。

最后:

希望本博客能在STM32单片机上给读者一定的帮助,省下找各种合并代码方案的时间成本。感谢各位观看,如有不足,欢迎在评论内留言与讨论。如果觉得写得好的,可以给我点赞+收藏+关注哦,再次感谢各位!

STM32——两个模块代码的合并相关推荐

  1. pycharm 如何将同一项目中不同模块代码分屏显示

    如图,想把这两个模块代码分屏显示 直接拖动其中一个代码的标签到另一个屏幕上 点击全屏显示

  2. QuartusII联合modelsim仿真时调用两个模块如何设置

    在QuartusII中Setting中simulation下添加Test bench如下图所示: 在Test bench中添加需要仿真调用的两个子模块代码如下图所示: 添加完后即可仿真!

  3. c语言实现两个有序链表的合并(代码示例)

    c语言实现两个有序链表的合并: 现有两个有序单链表,通过代码实现将两个单链表合并为一个有序的新表,要求使用旧表的空间,不能新分配内存 #include #include typedef struct ...

  4. Gitlab两个项目代码合并

    Gitlab两个项目之间的合并 目标 目标 因为公司有个项目在gitlab上分成了两个,所以特此记录下gitlab上两个项目合并的过程. 先确定好两个分支 target: A项目dev分支. sour ...

  5. c语言将两个有序表合并为一个有序表,c语言实现两个有序链表的合并(代码示例)...

    本篇文章通过代码示例介绍一下使用c语言合并两个有序链表的方法.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. 教程推荐:<c语言教程视频> c语言实现两个有序链表的合并 ...

  6. 基于Stm32的4G模块实现内网透传通信(代码后附)

    基于Stm32的4G模块实现内网透传通信 一.内网透传即内网映射,内网IP端口映射外网连接访问过程的实现.内网透传通信实现过程又有以下几种区别: 1)路由器映射.适合自己本地路由有公网IP网络环境,用 ...

  7. 【STM32】SPI 实验代码详解

    友情链接:[小项目关键技术]硬件通信三种方式.串口.IIC.SPI 文章目录 main.c spi.c spi.h SPI 是英语 Serial Peripheral interface 的缩写,顾名 ...

  8. 基于STM32的RC522模块读写数据块以及电子钱包充值扣款系统的设计

    目录 前言 STM32F103ZET6单片机 RC522 相关引脚连接 准备工作 Mifare卡 读卡过程 最终实现功能 代码 RC522.C代码 RC522.H main.c led.h 前言 本人 ...

  9. 【STM32训练—WiFi模块】第一篇、STM32驱动ESP8266WiFi模块获取网络时间

    目录 第一部分.写在前面 1.硬件准备 2.相关的AT指令 3.参考博客 第二部分.电脑串口助手调试ESP8266模块获取网络时间 1.ESP8266获取时间的流程 2.具体实现步骤 第三部分.STM ...

最新文章

  1. Protocol Buffer技术详解(语言规范)
  2. vuex实践之路——笔记本应用(三)
  3. 《Android开发艺术探索》自定义View中关于“HorizontalScrollViewEx”的改进
  4. Docker的常用管理命令Docker将数据挂载到容器的三种方式
  5. Linux下Web网站压力测试工具Webbench
  6. Test Report
  7. macos剪切_如何使用macOS的内置“ Kill and Yank”作为替代剪切和粘贴
  8. Ubuntu修复Fix Busybox Initramfs错误
  9. 移除项目中的CocoaPods
  10. Spring Boot入门(2)-项目属性配置
  11. 数学问题(一):进制转换
  12. vue强制刷新组件_Vue强制组件重新渲染
  13. 微机原理及应用简答题复习
  14. 2k21sports服务器暂时不可用,NBA2K20服务器不可用怎么解决 nba2k20进不去游戏解决办法...
  15. 转载-信息化与系统集成技术-全面解析工业4-0和云计算、大数据
  16. php中round(),PHP round( )用法及代码示例
  17. 操作系统OS-采用分段式存储管理不会产生内部碎片
  18. aop:aspectj-autoproxy
  19. 调用自定义模块出现ModuleNotFoundError: No module named ‘XXX‘的解决方案
  20. 万分之二用百分之怎么表示_百分比表示什么 什么是百分之多少是怎么算的?...

热门文章

  1. Ubuntu18.04挂载2T机械硬盘
  2. 进入无限咕咕咕的时代
  3. linux怎么同步系统时间同步,linux下时间同步的两种方法分享
  4. Python调用JS的四种方法
  5. 集成学习-Stacking算法
  6. 熊大UWB系列教程二:KEIL软件环境搭建以及程序下载
  7. win11右键显示更多选项关闭的四种方法
  8. 一个新的项目:狼人杀(三)
  9. babel.config.js 和 .babelrc
  10. ORACLE向表中添加数据