【 聲明:版權所有,歡迎轉載,請勿用于商業用途。 聯系信箱:feixiaoxing @163.com】
? ? ? ? 說完了上位機的開發,接下來就是固件的開發。前面我們說過,目前使用的開發板是極海apm32f103的開發板。它自身包含了iap示例,里面既有bootloader的代碼,也有app的代碼。所以,我們需要做的就是在app的基礎之上,添加自己需要的功能就可以了,bootloader就不用處理了。這也是大部分mcu模塊的開發方式。
1、修改中斷向量基地址和鏈接地址
? ? ? ? 這部分代碼如果不修改的話,我們需要每次通過bootloader來加載app的bin文件。這對于開發來說,不是很方便,所以這部分還是建議修改一下,等到最后部署的時候再改回來。其實,修改的地方就兩處,
#define FLASH_APP1_ADDR 0x0000
? ? ? ? 還有一處就是鏈接的地方,
2、添加新的串口
? ? ? ? 之前我們使用了debug串口,可以寫數據、讀數據。實際上開發的時候需要兩個串口,最好分開來。一個串口用于debug調試,一個用于和上位機之間的通信。現在是這么安排的,之前的debug串口,也就是pa9、pa10用于串口通信使用。這里重新添加一個usart3,用于調試使用,對應的pin腳是pb10、pb11,這部分可以通過廠家的芯片手冊查找到。其中,頭文件的定義如下所示,
#ifndef __USART3_H
#define __USART3_H#include "./SYSTEM/sys/sys.h"
#include "apm32f10x_usart.h"
#include <stdio.h>#define USART3_TX_GPIO_PORT GPIOB
#define USART3_TX_GPIO_PIN GPIO_PIN_10
#define USART3_TX_GPIO_CLK_ENABLE() do{ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOB); }while(0) #define USART3_RX_GPIO_PORT GPIOB
#define USART3_RX_GPIO_PIN GPIO_PIN_11
#define USART3_RX_GPIO_CLK_ENABLE() do{ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOB); }while(0) #define USART3_UX USART3
#define USART3_UX_IRQn USART3_IRQn
#define USART3_UX_IRQHandler USART3_IRQHandler
#define USART3_UX_CLK_ENABLE() do{ RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_USART3); }while(0) void usart3_init(uint32_t baudrate);
int sendChar(int ch);
void sendString(char* str);
void sendNumber(int num); #endif
? ? ? ? 具體的c實現代碼如下所示,
#include "./SYSTEM/usart3/usart3.h"
#include "apm32f10x_rcm.h"
#include "apm32f10x_gpio.h"
#include "apm32f10x_misc.h"void usart3_init(uint32_t baudrate)
{GPIO_Config_T gpio_init_struct = {0};USART_Config_T usart_init_struct = {0};USART3_UX_CLK_ENABLE();USART3_TX_GPIO_CLK_ENABLE();USART3_RX_GPIO_CLK_ENABLE();gpio_init_struct.pin = USART3_TX_GPIO_PIN;gpio_init_struct.speed = GPIO_SPEED_50MHz;gpio_init_struct.mode = GPIO_MODE_AF_PP;GPIO_Config(USART3_TX_GPIO_PORT, &gpio_init_struct);gpio_init_struct.pin = USART3_RX_GPIO_PIN;gpio_init_struct.speed = GPIO_SPEED_50MHz;gpio_init_struct.mode = GPIO_MODE_IN_PU;GPIO_Config(USART3_RX_GPIO_PORT, &gpio_init_struct);usart_init_struct.baudRate = baudrate; usart_init_struct.wordLength = USART_WORD_LEN_8B; usart_init_struct.stopBits = USART_STOP_BIT_1; usart_init_struct.parity = USART_PARITY_NONE; usart_init_struct.mode = USART_MODE_TX_RX; usart_init_struct.hardwareFlow = USART_HARDWARE_FLOW_NONE; USART_Config(USART3_UX, &usart_init_struct);USART_Enable(USART3_UX);
}int sendChar(int ch)
{while (USART3_UX->STS_B.TXCFLG == 0); USART3_UX->DATA_B.DATA = (uint16_t)ch; return ch;
}void sendString(char* str)
{char* pStart = str;while(*pStart){sendChar(*pStart);pStart++;}
}static void _sendNumber(int num)
{if(num > 9){sendNumber(num / 10);}num = num % 10;switch(num){case 0:sendChar('0');break;case 1:sendChar('1');break;case 2:sendChar('2');break;case 3:sendChar('3');break;case 4:sendChar('4');break;case 5:sendChar('5');break;case 6:sendChar('6');break;case 7:sendChar('7');break;case 8:sendChar('8');break;case 9:sendChar('9');break;default:break;}
}void sendNumber(int num)
{unsigned int val;if(num < 0){sendChar('-');val = -num;}else{val = num;}_sendNumber(val);
}
? ? ? ? 為了調試的方便,我們還實現了sendChar、sendString、sendNumber三個函數,到時候可以直接利用這幾個打印函數調試即可。
3、添加內部flash讀寫代碼
? ? ? ? 因為涉及到參數的保存,所以勢必涉及到內部flash的讀寫。這部分內容可以直接從對應的示例代碼中copy即可,
uint16_t apmflash_read_halfword(uint32_t faddr);
void apmflash_read(uint32_t raddr, uint16_t *pbuf, uint16_t length);
void apmflash_write_nocheck(uint32_t waddr, uint16_t *pbuf, uint16_t length);
void apmflash_write(uint32_t waddr, uint16_t *pbuf, uint32_t length);
void test_write(uint32_t waddr, uint16_t data);
4、添加adc代碼
? ? ? ? 和內部flash讀寫一樣,目前adc也有現成的case可以參考,所以相關代碼直接copy即可,
void adc_init(void);
uint16_t adc_get_result(uint8_t ch);
uint16_t adc_get_result_average(uint8_t ch, uint8_t times);
5、確認之前的串口接收協議
? ? ? ? 除了上面4點之外,還要確認下當前之前debug串口是否包含有接收功能,相關的邏輯是什么。通過仔細閱讀代碼,正好在中斷處理里面發現了相關的邏輯,
void USART_UX_IRQHandler(void)
{if (USART_ReadIntFlag(USART_UX, USART_INT_RXBNE) == SET){ g_rx_buffer[0] = USART_RxData(USART_UX); if ((g_usart_rx_sta & 0x8000) == 0) {if (g_usart_rx_sta & 0x4000) {if (g_rx_buffer[0] != 0x0A){g_usart_rx_sta = 0; }else{g_usart_rx_sta |= 0x8000; }}else {if (g_rx_buffer[0] == 0x0D){g_usart_rx_sta |= 0x4000;}else{g_usart_rx_buf[g_usart_rx_sta & 0x3FFF] = g_rx_buffer[0];g_usart_rx_sta++;if (g_usart_rx_sta > (USART_REC_LEN - 1)){g_usart_rx_sta = 0; }}}}USART_ClearIntFlag(USART_UX, USART_INT_RXBNE);}
}
6、gpio高低電平設定
? ? ? ? 這部分之前的demo已經設定好,直接skip即可。
7、總結
? ? ? ? 等我們想好要實現哪些功能的時候,其實做起來并不麻煩,關鍵是前面要規劃好。還有一點,就是要善于復用廠家給出的demo代碼,以及閱讀廠家的芯片手冊,這些第一手的資料不一定文檔上能找到,只能自己通過文檔閱讀的方法一點、一點去挖掘,總是可以解決的。
? ? ? ? 最后要提及的就是版本管理,非常推薦大家在本地用git把代碼管起來。不管過分相信自己的記憶力,好記憶不如爛筆頭。回到代碼本身,就是好記憶不如git軟件好使。