Keil 5 中的代码模块化封装

在学习89C52时,当需要编写又臭又长的代码时,会使用到代码的模块化封装,在Keil5中也可以这样进行,因为接下来是小车的项目所以代码会很长,这章作为一个简单的预备知识。

演示就在上节完成的DHT11 & LCD1602的项目中进行:

1. 想要创建新的C文件,其目录应该和main.c等一系列的所属目录一样,所以先查看main.c等c文件的目录:

按照该目录去电脑中查找:

C:\mjm_CubeMX_proj\mjm_dht11_lcd1602_proj\Core

如上图所示,在每个项目里的 Core 文件中,有 IncSrc 两个文件夹,Src 就是用来保存c文件的;Inc 就是用来保存h文件的。

2. 在 Src 文件内创建两个c文件,LCD1602.cDHT11.c

3.  在 Inc 文件内创建两个c文件,LCD1602.h DHT11.h

 

4. 在Keil中,添加这些 c文件 和 h文件 

4.1 选择刚刚添加文件的Core路径: 

 

 4.2 点击 Add Files:

上图是Core的下一级路径,所以点击上一级,然后找到Core,找到需要添加的文件:

 4.3 添加完之后:

可见,最右侧已经将两个C文件包含进来了,此时点击下方的OK,就会自动把h文件同样也包含进来。

5. 点击编译

6. 在LCD1602.c中:

6.1 include h 文件

在LCD1602.c 中必须添加“LCD1602.h”的文件,然后按需添加其他h文件

#include "LCD1602.h"
#include "DHT11.h" //要用到在DHT11.c中定义的 微秒级别延迟函数
#include "gpio.h"
#include "tim.h"
6.2 写相关代码
void write(char flag_w, char cmd) //write(1,cmd)代表写内容;write(0,cmd)代表写指令
{
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET); //RW全程置0
	
	if(flag_w == 1){
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); //RS置1写内容
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET); //E置0
		TIM2_Delay_us(2);
		
		GPIOA->ODR = cmd; //根据时序图,E为0时开始传内容
		
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); //E置1
		HAL_Delay(5);
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET); //E置0
		HAL_Delay(5);
	}
	
	if(flag_w == 0){
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); //RS置0写指令
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET); //E置0
		TIM2_Delay_us(2);
		
		GPIOA->ODR = cmd; //根据时序图,E为0时开始传内容
		
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); //E置1
		HAL_Delay(5);
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET); //E置0
		HAL_Delay(5);
	}
	
}
 

 
void Init()
{
	HAL_Delay(15);
	write(0,0x38);
	HAL_Delay(5);
	
	//detectBusy();
	write(0,0x38);
	//detectBusy();
	write(0,0x08);
	//detectBusy();
	write(0,0x01);
	//detectBusy();
	write(0,0x06);
	//detectBusy();
	write(0,0x0C);
	
}
 
void showStr(char *msg, char hang, char lie)
{
	char pos;
	
	if(hang == 0){//如果第一行
			pos = 0x80 + 0x00 + lie; 
	}else if(hang == 1){//如果第二行
			pos = 0x80 + 0x40 + lie;
	}
	//detectBusy();
	write(0,pos); //只要定下开始的位置,之后光标会自行移动
	
	while(*msg != '\0'){
		//detectBusy();
		write(1,*msg);
		msg++;
	}
		
}
6.3 再次编译,然后就可以在左侧的LCD1602.c的目录里找到LCD1602.h了:

此时,就可以在h文件中添加可能会被外部调用的函数了:

注意,和之前不同的是,还必须写一下申明:

代码格式就是:

#ifndef __XXXX_H__ // "XXXX"就是h文件的名字
#define __XXXX_H__

/
//此处就是可能被外部调用的函数名
/


#endif 
//必须在程序最后加上一个新行,不然会有warning

Init函数在89C52时,如果进行封装直接写 void Init( ); 就可以,但是在32的封装中必须里面加个“void”,否则会有warning

7. 在DHT11.c 中:

遵循和LCD1602.c 相同的步骤

7.1 include h 文件
#include "DHT11.h"
#include "gpio.h"
#include "tim.h"
7.2 写相关代码
char buffer;
char datas[5];
char temp[9];
char huma[9];

void TIM2_Delay_us(uint16_t n_us) //使用TIM2来做us级延时函数
{
/* 使能定时器2计数 */
	__HAL_TIM_ENABLE(&htim2);
	__HAL_TIM_SetCounter(&htim2, 0);
	while(__HAL_TIM_GetCounter(&htim2) < ((1 * n_us)-1) );
/* 关闭定时器2计数 */
	__HAL_TIM_DISABLE(&htim2);
}

void DHT_GPIO_Init(uint32_t Mode)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOB_CLK_ENABLE();
	GPIO_InitStruct.Pin = GPIO_PIN_7;
	GPIO_InitStruct.Mode = Mode;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
 7.3 再次编译,找到并修改h文件:

 8. 在main函数中 添加h文件写代码

#include "stdio.h"
#include "LCD1602.h"
#include "DHT11.h"

extern char temp[9];
extern char huma[9];

int fputc(int a, FILE *f) //一个字符一个字符发送
{
	unsigned char temp[1] = {a};
	HAL_UART_Transmit(&huart1, temp, 1, 0xffff);
	return a;
}

int main(void)
{

  Init(); //LCD1602初始化

  while (1)
  {
		HAL_Delay(1000);
		showDataFromDHT();	
		Build_Datas();
		
		printf(temp);
		printf("\r\n");
		printf(huma);
		printf("\r\n");
		
		showStr(temp,0,4);
		showStr(huma,1,4);

  }
}

 至此,封装完成!

 

 

 

 

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
由于ZigBee协议和硬件平台的多样性,编写ZigBee协调器代码需要基于具体的芯片和开发板进行开发。以下是一般步骤: 1. 准备开发环境:安装Keil5和芯片厂商提供的开发包,准备好开发板和USB转串口模块等。 2. 创建新项目:在Keil5创建一个新的项目,选择芯片型号,并设置工作区和输出路径等。 3. 编写代码:根据ZigBee协议栈和芯片厂商提供的API文档,编写ZigBee协调器的代码,包括初始化、网络配置、数据收发等功能。 4. 调试和测试:将编写好的代码下载到开发板,通过串口连接调试工具,调试和测试代码是否正确。 以下是一个基于TI CC2530芯片的ZigBee协调器示例代码: ```c #include "ZComDef.h" #include "AF.h" #include "OSAL.h" #include "OSAL_Tasks.h" #include "ZDApp.h" #include "ZDObject.h" #include "ZDProfile.h" #include "ZDConfig.h" #include "DebugTrace.h" #include "MT.h" #include "MT_SYS.h" #include "MT_APP.h" /* 事件定义 */ #define APP_EVT_START_DEVICE 0x0001 #define APP_EVT_SEND_MSG 0x0002 #define APP_EVT_RECV_MSG 0x0004 /* 定义消息结构体 */ typedef struct { osal_event_hdr_t hdr; uint8 cmdId; uint8 dataLen; uint8 *pData; } appMsg_t; /* 定义全局变量 */ uint8 appTaskId; // 任务ID uint8 appEndpoint = 1; // 端点号 uint8 appState; // 状态 uint8 appSeqNum = 0; // 序列号 uint16 appShortAddr = 0; // 短地址 uint16 appPanId = 0x1234; // PAN ID uint8 appChannel = 11; // 频道 uint8 appDestAddr[] = {0x00, 0x00}; // 目标地址 uint8 appMsgData[] = {0x01, 0x02, 0x03}; // 消息数据 /* 声明函数 */ void appInit(void); uint16 appProcessEvent(uint8 taskId, uint16 events); void appSendData(uint16 destAddr, uint8 *pData, uint8 dataLen); void appRecvData(uint16 srcAddr, uint8 *pData, uint8 dataLen); /* 定义任务处理函数 */ uint16 appProcessEvent(uint8 taskId, uint16 events) { // 处理开始设备事件 if (events & APP_EVT_START_DEVICE) { // 初始化ZigBee协议栈 ZDOInit(); // 设置ZigBee协议栈参数 ZDO_Configuration(appChannel, appPanId, TRUE); // 启动ZigBee协议栈 ZDApp_Startup(appTaskId); // 发送广播消息 appSendData(0xFFFF, appMsgData, sizeof(appMsgData)); // 设置状态为运行 appState = 1; return events ^ APP_EVT_START_DEVICE; } // 处理发送消息事件 if (events & APP_EVT_SEND_MSG) { // 发送消息 appSendData(appShortAddr, appMsgData, sizeof(appMsgData)); return events ^ APP_EVT_SEND_MSG; } // 处理接收消息事件 if (events & APP_EVT_RECV_MSG) { // 处理接收到的消息 // ... return events ^ APP_EVT_RECV_MSG; } return 0; } /* 定义初始化函数 */ void appInit(void) { // 初始化任务ID appTaskId = osal_add_task(appProcessEvent, 0); // 注册ZigBee协议栈回调函数 ZDApp_RegisterForZDOMsg(appTaskId, MSG_CB_APP); // 注册AF回调函数 AF_Register(appTaskId); // 注册端点 AF_RegisterEndpoint(appEndpoint, appRecvData); // 注册MT回调函数 MT_RegisterAppCB(appTaskId); // 发送开始设备事件 osal_set_event(appTaskId, APP_EVT_START_DEVICE); } /* 定义发送数据函数 */ void appSendData(uint16 destAddr, uint8 *pData, uint8 dataLen) { afAddrType_t afAddr; // 设置目标地址 afAddr.addrMode = (destAddr == 0xFFFF) ? afAddrModeBroadcast : afAddrMode16Bit; afAddr.endPoint = appEndpoint; afAddr.addr.shortAddr = destAddr; // 封装消息 AF_DataRequest(&afAddr, &appSeqNum, 0, 0, 0, 0, dataLen, pData, NULL); } /* 定义接收数据函数 */ void appRecvData(uint16 srcAddr, uint8 *pData, uint8 dataLen) { // 发送接收消息事件 appMsg_t *pMsg = (appMsg_t *)osal_msg_allocate(sizeof(appMsg_t) + dataLen); pMsg->hdr.event = APP_EVT_RECV_MSG; pMsg->cmdId = 0; pMsg->dataLen = dataLen; pMsg->pData = (uint8 *)(pMsg + 1); osal_memcpy(pMsg->pData, pData, dataLen); osal_msg_send(appTaskId, (uint8 *)pMsg); } /* 主函数 */ void main(void) { // 初始化 appInit(); // 循环处理事件 while (1) { osal_run_system(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值