本帖最后由 周亚龙 于 2018-8-25 22:14 编辑
上个月接触到了一套谷雨NB-IOT开发板代码,看的本人颇为费神。代码中使用了大量的结构体嵌套结构体指向函数的指针来封装整个代码。着实让我摸不到头脑。请教大神之后,让我耐心去看,并且要熟悉这种代码框架,刚从本科学校出来,公司才干了四个月,写代码对我来说确实只是袖子撸起来,直接上去干。劳资写代码从来不思考什么程序架构,实现功能再说,我管他那么多。直道遇到这篇文章。
以下为CSDN转载:
C语言编程代码架构搭建——代码分层 ///////////////////////////////////////////////////////////////// 底层驱动 初始化配置表 硬件抽象层 对GPIO抽象化 中间交换层 接收缓存区设置 变量标志位 系统任务调用层 基本检测测试任务 软件协议处理任务 硬件控制处理任务 DEBUG调试模式 像Linux一样打印系统运行时间 /////////////////////////////////////////////////////////////////////////
编程代码前遵循结构设计,大体分为三部分,底层驱动,硬件抽象层,系统任务调用层,程序设计按照这部分来进行设计。 底层驱动: 底层驱动是对应相应的MCU而制定的,与MCU的库函数,开发环境搭建有关,底层驱动是将项目所需要的功能进行一系列的初始化,并将基础的功能封装成一个个函数供顶层任务层调用。以STM32为例,底层驱动设计框架如下图所示。 file:///C:/Users/123/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg 初始化配置表配置表的设置需要根据项目的需求而添加,例如系统初始化WiFi模块时需要配置IP地址,RTC时间初始化需要给定一个具体时间等,这些可以通过写一个初始化配置表,在初始化驱动的时候将里面的值传进驱动的代码中。例如 //网络配置表struct Network_status Dev_Network_status = {
.u8gateway = "192.168.1.1",
.u8DevIP_addr = "192.168.1.101",
.u8Target_host_addr = "192.168.1.100",
.u32port = 9090,
.u8net_mask = "255.255.255.0",};
//RTC时间配置表
struct RTC_Timer Dev_RTC_Timer_config = {
.u32Year = 2016,
.u32Month = 7,
.u32Day = 15,
.u32Hour = 23,
.u32Minute = 45,
.u32Second = 30,
.u32DayOfWeek = RTC_SATURDAY,
.u32TimeScale = RTC_CLOCK_24, };
硬件抽象层硬件抽象层将任务与底层驱动区分开来,将硬件驱动功能抽象化,把底层硬件抽象成操作函数,供系统层调用 对GPIO抽象化在底层,GPIO模块子程序中将GPIO管脚配置的函数赋值给probe结构体,然后调用硬件抽象层获取函数,使得硬件抽象层获得驱动信息。
底层GPIO.c部分代码。 static void Dev_GPIO_Set_Value(const uint8_t Lock_number,const uint8_t value);
static uint8_t Dev_GPIO_Detect_Value(const uint8_t Lock_number);
void Dev_GPIO_probe(void *PGPIO_struct)
{ …………………………………………………..
PGPIO_info->GPIO_Set_Value = Dev_GPIO_Set_Value; //底层驱动接口
PGPIO_info->GPIO_Detect_Value = Dev_GPIO_Detect_Value;
Get_Dev_gpio_info(PGPIO_info);
//硬件抽象层获取底层驱动资源配置
………………………………………………}· 1· 2· 3· 4· 5· 6· 7· 8· 9· 10· 11· 12· 13· 14硬件抽象层将获取的资源封装在函数里面供系统任务调用 硬件抽象层System_Hardware.c部分代码 static struct GPIO_data *PDirver_to_GPIO_data = NULL;
void Get_Dev_gpio_info(void *PDev_gpio_info) //获取底层驱动资源函数
{
PDirver_to_GPIO_data = (struct GPIO_data *)PDev_gpio_info;
}
void gpio_set_value(const uint8_t gpio,const uint8_t value) //任务调用层调用函数
//从此感觉写代码就是写文章,若是你的代码让别人看着没有一些惊喜,一些巧妙的地方。那读起来不过是大白话,没有任何艺术可言本人的LED灯函数:请大家批评指针
使用了滴答定时器作为系统任务总的时间控制
//LED 流动驱动函数(三个LED灯的参数)
//参数 LED 使能参数
//led0_ms LED0 的延时时间
//例如 110 LED2使能 LED1使能 LED0失能
void LED_drive_Poll(unsigned char LED_enable,int led0_ms,int led1_ms,int led2_ms)
{
static unsigned int LED0_time_ms = 0; //记录LED0任务时间
static unsigned int LED0_time_s = 0;
static unsigned int LED1_time_ms = 0; //记录LED1任务时间
static unsigned int LED1_time_s = 0;
static unsigned int LED2_time_ms = 0; //记录LED2任务时间
static unsigned int LED2_time_s = 0;
static unsigned char i = 1;
if(LED_enable <= 7) //参数判断
{
if(i == 1) //只获取第一次
{
LED0_time_s = TASK_time_s; //获取时间戳
LED0_time_ms = TASK_time_ms;
LED1_time_s = TASK_time_s; //获取时间戳
LED1_time_ms = TASK_time_ms;
LED2_time_s = TASK_time_s; //获取时间戳
LED2_time_ms = TASK_time_ms;
i++;
}
if(LED_enable & 0x01) //LED0使能
{
if((TASK_time_s*1000+TASK_time_ms) - (LED0_time_s*1000 + LED0_time_ms) >= led0_ms) //是延时时间的整倍数
{ //延时之后
LED0 = !LED0; //延时时间到就取反
//重新获取时间戳
LED0_time_s = TASK_time_s; //获取时间戳
LED0_time_ms = TASK_time_ms;
}
}
if(LED_enable & 0x02) //LED1使能
{
if((TASK_time_s*1000+TASK_time_ms) - (LED1_time_s*1000 + LED1_time_ms) >= led1_ms) //是延时时间的整倍数
{ //延时之后
LED1 = !LED1; //延时时间到就取反
//重新获取时间戳
LED1_time_s = TASK_time_s; //获取时间戳
LED1_time_ms = TASK_time_ms;
}
}
if(LED_enable & 0x04) //LED1使能
{
if((TASK_time_s*1000+TASK_time_ms) - (LED2_time_s*1000 + LED2_time_ms) >= led2_ms) //是延时时间的整倍数
{ //延时之后
LED2 = !LED2; //延时时间到就取反
//重新获取时间戳
LED2_time_s = TASK_time_s; //获取时间戳
LED2_time_ms = TASK_time_ms;
}
}
}
}
以下为滴答设置与中断
unsigned int TASK_time_ms = 0; //任务总时间
unsigned int TASK_time_s = 0; //滴答定时器时钟配置初始化
void systick_init() //滴答定时器时钟初始化
{ //if(SysTick_Config(SystemFrequency/100000))
if(SysTick_Config(SystemCoreClock/1000)) //1ms中断一次
{
//ERROR
while(1);
}
}
//滴答定时器中断服务函数
//硬件自动重载
void SysTick_Handler(void)
{
TASK_time_ms++;
if(TASK_time_ms >= 1000)
{
TASK_time_s++; //最大为65535S 约为 18个小时
TASK_time_ms = 0;
}
}
//抛转引玉,因为心有所悟,感觉自己的境界稍微进步,请批评指针(打了半天空格!)
|