文章背景:
作為一個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); //使能指定的ADC1
ADC_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); //串口初始化為115200
Adc_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單片機上給讀者一定的幫助,省下找各種合并代碼方案的時間成本,感謝各位觀看,如有不足,歡迎在評論內留言與討論,如果覺得寫得好的,可以給我點贊+收藏+關注哦,再次感謝各位!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/255964.html
標籤:其他
下一篇:HSC490控制器除錯筆記(一)
