在学习89C52时,当需要编写又臭又长的代码时,会使用到代码的模块化封装,在Keil5中也可以这样进行,因为接下来是小车的项目所以代码会很长,这章作为一个简单的预备知识。
演示就在上节完成的DHT11 & LCD1602的项目中进行:
1. 想要创建新的C文件,其目录应该和main.c等一系列的所属目录一样,所以先查看main.c等c文件的目录:
按照该目录去电脑中查找:
C:\mjm_CubeMX_proj\mjm_dht11_lcd1602_proj\Core
如上图所示,在每个项目里的 Core 文件中,有 Inc 和 Src 两个文件夹,Src 就是用来保存c文件的;Inc 就是用来保存h文件的。
2. 在 Src 文件内创建两个c文件,LCD1602.c 和 DHT11.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);
}
}
至此,封装完成!