一、项目概述1.1 实验名称DS18B20 温度传感器综合实验LCD 分页显示 多阈值提示 串口打印 LED 状态指示1.2 硬件平台STM32F103系统时钟 72MHz标准库 StdPeriph1.3 硬件接线表格外设STM32 引脚说明DS18B20 数据 DQPA15(J14-P37)单总线通讯LCD1602 控制脚PB0(RS)、PB1(RW)、PB2(E)8 位 / 4 位接口可选LCD1602 数据脚PB8~PB15D0~D7LED1自定义 LED 引脚led.h200ms 周期闪烁USART1PA9(TX)、PA10(RX)9600 波特串口输出温度1.4 核心功能DS18B20 硬件上电自检无传感器持续报错提示每 500ms 采集一次环境温度串口实时打印正负温度LED1 每 200ms 翻转作为系统运行心跳指示灯LCD1602 双页面自动切换3 秒翻页一次页面 0实时温度数值显示页面 1多区间温度温馨提示温度阈值分级提示低温保暖、舒适、通风、高温防暑四级支持正负温度换算DS18B20 单总线标准读写时序SysTick 毫秒 / 微秒高精度延时串口重定向 printf 输出。1.5 运行时序参数系统基础循环10msLED 闪烁周期200ms20 个 10ms 计数温度采集周期500ms50 个 10ms 计数LCD 页面切换周期3000ms300 个 10ms 计数二、宏定义与全局参数说明2.1 温度阈值宏main.cc运行#define TEMP_LOW 18.0f // 低温分界低于此值提示保暖 #define TEMP_COMORT 26.0f // 舒适温度上限 #define TEMP_HIGH 32.0f // 高温预警分界温度分级逻辑temp 18.0℃Keep Warm! 气温偏低注意保暖18.0 ≤ temp 26.0℃Very Comfort 舒适温度区间26.0 ≤ temp 32.0℃Ventilate! 温度偏高建议通风temp ≥32.0℃Heat Stroke! 高温防暑预警2.2 核心全局变量main 主函数表格变量名类型作用tick_cntuint16_t10ms 基础计数器驱动 LED、温度采集定时temp_valfloat存储 DS18B20 读取的浮点温度lcd_buf[16]charLCD 字符串缓存存放温度 / 提示文本page_flaguint8_t页面标记0 温度页1 提示页page_timeruint16_t翻页计时器满 300 清零切换页面三、分模块代码详细说明模块 1main.c 主逻辑模块3.1 外设初始化流程SysTick_Init(72)配置 72MHz 系统时钟延时分频提供delay_ms/delay_usNVIC_PriorityGroupConfig中断优先级分组 2LED_Init()初始化 LED 指示灯 IOUSART1_Init(9600)串口 1 初始化开启收发中断重定向 printflcd1602_init()LCD1602 屏幕初始化清屏、设置显示模式DS18B20 硬件检测循环反复复位读取传感器异常则 LCD 报错 串口打印。3.2 主循环定时逻辑10ms 单次循环计数器自增、延时 10msLED 心跳每 20 次循环200ms翻转 LED 电平翻页计时page_timer 计数到 3003s切换页面标记清屏温度采集每 50 次循环500ms读取一次 DS18B20 温度串口打印区分正负温度格式化输出LCD 页面渲染根据 page_flag 刷新对应页面文字。3.3 LCD 分页显示逻辑页面 0温度页第一行固定标题Current Temp第二行打印浮点温度页面 1提示页第一行标题Warm Tip:第二行根据温度阈值匹配提示字符串页面切换时执行lcd1602_clear()清屏避免文字重叠。3.4 负温度处理逻辑DS18B20 负数为补码存储读取后取反 1 换算绝对值输出负号。模块 2ds18b20.c 单总线驱动模块DS18B20 标准单总线时序驱动实现 IO 切换、复位、位读写、字节读写、温度转换。2.1 底层 IO 切换函数DS18B20_IO_IN()DQ 引脚配置为上拉输入用于读取传感器应答DS18B20_IO_OUT()DQ 引脚配置推挽输出主机拉低 / 拉高总线。2.2 基础时序函数DS18B20_Reset()主机拉低总线 750us 复位传感器释放等待应答DS18B20_Check()等待传感器拉低总线存在脉冲返回 0 检测到1 无设备DS18B20_Read_Bit()读取单总线 1bit标准读写时序拉低 2us释放 12us 采样DS18B20_Read_Byte()循环读取 8bit组合为 1 字节低位先读DS18B20_Write_Byte()逐位写入字节写 0 保持 60us 低电平写 1 仅 2us 低电平。2.3 功能接口函数DS18B20_Start()跳过 ROM 指令 (0xCC) 启动温度转换 (0x44)DS18B20_Init()开启 PA15 时钟、关闭 JTAG 调试、配置输出模式复位并检测传感器DS18B20_GetTemperture()完整温度读取流程启动转换 → 复位 → 跳过 ROM → 读取暂存器 (0xBE)读取低字节 LSB、高字节 MSB拼接 16 位原始数据判断符号位正负温度换算分辨率 0.0625℃/LSB返回浮点温度值。模块 3usart.c 串口驱动模块3.1 功能说明PA9 复用推挽 TXPA10 浮空 RX9600 波特 8N1 串口开启收发中断fputc重定向标准输出支持printf()打印中断回调函数接收数据自动回显串口回环测试。3.2 关键函数USART1_Init(u32 bound)串口时钟、GPIO、波特率、中断 NVIC 初始化USART1_IRQHandler()接收中断服务函数回显收到字节fputc()底层字符发送printf 依赖此函数输出。模块 4SysTick.c 高精度延时模块基于内核 SysTick 定时器AHB/8 分频提供微秒、毫秒阻塞延时。4.1 全局分频变量fac_us1 微秒所需计数fac_ms1 毫秒所需计数。4.2 核心接口SysTick_Init(u8 SYSCLK)根据系统时钟初始化分频系数delay_us(u32 nus)微秒级阻塞延时delay_ms(u16 nms)毫秒级阻塞延时72MHz 最大支持 1864ms 单次延时。模块 5lcd1602.c LCD1602 驱动模块支持 8 位并行 / 4 位半并行两种接口通过宏LCD1602_4OR8_DATA_INTERFACE切换。5.1 IO 资源控制口PB0 (RS)、PB1 (RW)、PB2 (E)数据口PB8~PB15D0~D7。5.2 底层函数lcd1602_gpio_init()初始化 LCD 所有 IO 为推挽输出lcd_set_dataport()将 8 位数据写入 PB8~PB15lcd1602_write_cmd()写指令函数分 4/8 位重载lcd1602_write_data()写显示数据函数分 4/8 位重载。5.3 应用接口lcd1602_init()LCD 上电初始化功能设置、显示开启、自动右移、清屏lcd1602_clear()发送 0x01 清屏指令lcd1602_show_string(x,y,str)指定坐标 (x:0~15,y:0/1) 显示字符串自动换行截断。四、数据流程说明上电初始化全部外设循环检测 DS18B20 硬件每 500ms 调用DS18B20_GetTemperture()获取浮点温度温度值同步两路输出USART1 串口格式化打印LCD1602 双页面定时轮播显示LED 持续 200ms 闪烁证明程序正常运行无卡死3 秒自动切换 LCD 页面温度区间自动匹配提示文字。五、异常处理机制DS18B20 缺失while 死循环LCD 固定显示报错文字串口持续打印故障提示负温度兼容补码自动换算串口输出带负号LCD 坐标越界保护lcd1602_show_string判断 x/y 范围超出直接退出不操作屏幕SysTick 延时溢出限制delay_ms单次最大 1864ms本项目使用 10ms 短延时无溢出风险。六、编译与配置说明编译环境Keil MDK-ARMSTM32F10x_StdPeriph_Lib 标准库必须头文件依赖stdio.hprintf/sprintf、string.hmemset/strcpy、math.hfabs 浮点绝对值宏配置项DS18B20 端口宏DS18B20_PORT、DS18B20_PIN、DS18B20_PORT_RCCLCD 接口模式LCD1602_4OR8_DATA_INTERFACE08 位14 位LCD 控制 / 数据端口宏LCD_CTRL_PORT、LCD_DATA_PORT、对应引脚宏JTAG 关闭GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE)释放 PA15 作为 DS18B20 总线。七、实验现象对照文档上电无 DS18B20LCD 两行显示DS18B20 ERROR / Check Sensor!串口持续打印故障传感器正常识别串口打印DS18B20检测成功!LED1 200ms 周期性闪烁LCD 页面 00~3s第一行 Current Temp第二行实时温度如25.62 CLCD 页面 13~6s第一行 Warm Tip:第二行根据温度显示对应提示语句串口每 500ms 输出一行温度负数自动显示负号每 3 秒 LCD 清屏切换页面循环往复。八、核心代码//main.c #include lcd1602.h // IO初始化 void lcd1602_gpio_init(void) { GPIO_InitTypeDef gpio_cfg; RCC_APB2PeriphClockCmd(LCD_CTRL_RCC, ENABLE); // 控制脚 PB0 PB1 PB2 推挽输出 gpio_cfg.GPIO_Pin LCD_E_PIN | LCD_RS_PIN | LCD_RW_PIN; gpio_cfg.GPIO_Mode GPIO_Mode_Out_PP; gpio_cfg.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(LCD_CTRL_PORT, gpio_cfg); // 数据脚 PB8~PB15 推挽输出 gpio_cfg.GPIO_Pin LCD_DATA_MASK; gpio_cfg.GPIO_Mode GPIO_Mode_Out_PP; gpio_cfg.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(LCD_DATA_PORT, gpio_cfg); LCD_RS_L(); LCD_RW_L(); LCD_E_L(); } // 将8位数据输出到PB8~PB15D0→PB8D7→PB15 static void lcd_set_dataport(uint8_t val) { // 先清除PB8~PB15 LCD_DATA_PORT-ODR ~(0xFF 8); // val低8位移到PB8~PB15输出 LCD_DATA_PORT-ODR | ((uint16_t)val 8); } // 写命令 #if (LCD1602_4OR8_DATA_INTERFACE 0) void lcd1602_write_cmd(uint8_t cmd) { LCD_RS_L(); LCD_RW_L(); LCD_E_L(); lcd_set_dataport(cmd); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); } #else void lcd1602_write_cmd(uint8_t cmd) { LCD_RS_L(); LCD_RW_L(); LCD_E_L(); lcd_set_dataport(cmd 4); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); lcd_set_dataport(cmd 0x0F); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); } #endif // 写数据 #if (LCD1602_4OR8_DATA_INTERFACE 0) void lcd1602_write_data(uint8_t dat) { LCD_RS_H(); LCD_RW_L(); LCD_E_L(); lcd_set_dataport(dat); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); } #else void lcd1602_write_data(uint8_t dat) { LCD_RS_H(); LCD_RW_L(); LCD_E_L(); lcd_set_dataport(dat 4); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); lcd_set_dataport(dat 0x0F); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); } #endif // LCD初始化 #if (LCD1602_4OR8_DATA_INTERFACE 0) void lcd1602_init(void) { lcd1602_gpio_init(); delay_ms(20); lcd1602_write_cmd(0x38); lcd1602_write_cmd(0x0C); lcd1602_write_cmd(0x06); lcd1602_write_cmd(0x01); } #else void lcd1602_init(void) { lcd1602_gpio_init(); delay_ms(20); lcd1602_write_cmd(0x28); lcd1602_write_cmd(0x0C); lcd1602_write_cmd(0x06); lcd1602_write_cmd(0x01); } #endif // 清屏 void lcd1602_clear(void) { lcd1602_write_cmd(0x01); } // 显示字符串 x:0~15 y:0/1 void lcd1602_show_string(uint8_t x, uint8_t y, uint8_t *str) { uint8_t i 0; if(y 1 || x 15) return; if(y 0) { while(*str ! \0) { if(i 16 - x) lcd1602_write_cmd(0x80 i x); else lcd1602_write_cmd(0x80 0x40 i x - 16); lcd1602_write_data(*str); str; i; } } else { while(*str ! \0) { if(i 16 - x) lcd1602_write_cmd(0x80 0x40 i x); else lcd1602_write_cmd(0x80 i x - 16); lcd1602_write_data(*str); str; i; } } }//ds18b20.c #include ds18b20.h #include SysTick.h /******************************************************************************* * 函 数 名 : DS18B20_IO_IN * 函数功能 : DS18B20_IO输入配置 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void DS18B20_IO_IN(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_PinDS18B20_PIN; GPIO_InitStructure.GPIO_ModeGPIO_Mode_IPU; GPIO_Init(DS18B20_PORT,GPIO_InitStructure); } /******************************************************************************* * 函 数 名 : DS18B20_IO_OUT * 函数功能 : DS18B20_IO输出配置 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void DS18B20_IO_OUT(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_PinDS18B20_PIN; GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz; GPIO_InitStructure.GPIO_ModeGPIO_Mode_Out_PP; GPIO_Init(DS18B20_PORT,GPIO_InitStructure); } /******************************************************************************* * 函 数 名 : DS18B20_Reset * 函数功能 : 复位DS18B20 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void DS18B20_Reset(void) { DS18B20_IO_OUT(); //SET PG11 OUTPUT DS18B20_DQ_OUT0; //拉低DQ delay_us(750); //拉低750us DS18B20_DQ_OUT1; //DQ1 delay_us(15); //15US } /******************************************************************************* * 函 数 名 : DS18B20_Check * 函数功能 : 检测DS18B20是否存在 * 输 入 : 无 * 输 出 : 1:未检测到DS18B20的存在0:存在 *******************************************************************************/ u8 DS18B20_Check(void) { u8 retry0; DS18B20_IO_IN();//SET PG11 INPUT while (DS18B20_DQ_INretry200) { retry; delay_us(1); }; if(retry200)return 1; else retry0; while (!DS18B20_DQ_INretry240) { retry; delay_us(1); }; if(retry240)return 1; return 0; } /******************************************************************************* * 函 数 名 : DS18B20_Read_Bit * 函数功能 : 从DS18B20读取一个位 * 输 入 : 无 * 输 出 : 1/0 *******************************************************************************/ u8 DS18B20_Read_Bit(void) // read one bit { u8 data; DS18B20_IO_OUT();//SET PG11 OUTPUT DS18B20_DQ_OUT0; delay_us(2); DS18B20_DQ_OUT1; DS18B20_IO_IN();//SET PG11 INPUT delay_us(12); if(DS18B20_DQ_IN)data1; else data0; delay_us(50); return data; } /******************************************************************************* * 函 数 名 : DS18B20_Read_Byte * 函数功能 : 从DS18B20读取一个字节 * 输 入 : 无 * 输 出 : 一个字节数据 *******************************************************************************/ u8 DS18B20_Read_Byte(void) // read one byte { u8 i,j,dat; dat0; for (i1;i8;i) { jDS18B20_Read_Bit(); dat(j7)|(dat1); } return dat; } /******************************************************************************* * 函 数 名 : DS18B20_Write_Byte * 函数功能 : 写一个字节到DS18B20 * 输 入 : dat要写入的字节 * 输 出 : 无 *******************************************************************************/ void DS18B20_Write_Byte(u8 dat) { u8 j; u8 testb; DS18B20_IO_OUT();//SET PG11 OUTPUT; for (j1;j8;j) { testbdat0x01; datdat1; if (testb) { DS18B20_DQ_OUT0;// Write 1 delay_us(2); DS18B20_DQ_OUT1; delay_us(60); } else { DS18B20_DQ_OUT0;// Write 0 delay_us(60); DS18B20_DQ_OUT1; delay_us(2); } } } /******************************************************************************* * 函 数 名 : DS18B20_Start * 函数功能 : 开始温度转换 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void DS18B20_Start(void)// ds1820 start convert { DS18B20_Reset(); DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip rom DS18B20_Write_Byte(0x44);// convert } /******************************************************************************* * 函 数 名 : DS18B20_Init * 函数功能 : 初始化DS18B20的IO口 DQ 同时检测DS的存在 * 输 入 : 无 * 输 出 : 1:不存在0:存在 *******************************************************************************/ u8 DS18B20_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(DS18B20_PORT_RCC,ENABLE); GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE); GPIO_InitStructure.GPIO_PinDS18B20_PIN; GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz; GPIO_InitStructure.GPIO_ModeGPIO_Mode_Out_PP; GPIO_Init(DS18B20_PORT,GPIO_InitStructure); DS18B20_Reset(); return DS18B20_Check(); } /******************************************************************************* * 函 数 名 : DS18B20_GetTemperture * 函数功能 : 从ds18b20得到温度值 * 输 入 : 无 * 输 出 : 温度数据 *******************************************************************************/ float DS18B20_GetTemperture(void) { u16 temp; u8 a,b; float value; DS18B20_Start(); // ds1820 start convert DS18B20_Reset(); DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip rom DS18B20_Write_Byte(0xbe);// convert aDS18B20_Read_Byte(); // LSB bDS18B20_Read_Byte(); // MSB tempb; temp(temp8)a; if((temp0xf800)0xf800) { temp(~temp)1; valuetemp*(-0.0625); } else { valuetemp*0.0625; } return value; } #ifndef _ds18b20_H #define _ds18b20_H #include system.h /* DS18B20时钟端口、引脚定义 */ #define DS18B20_PORT GPIOA #define DS18B20_PIN (GPIO_Pin_15) #define DS18B20_PORT_RCC RCC_APB2Periph_GPIOA ////IO操作函数 #define DS18B20_DQ_OUT PAout(15) //数据端口 #define DS18B20_DQ_IN PAin(15) //数据端口 u8 DS18B20_Init(void); //初始化DS18B20 float DS18B20_GetTemperture(void); //获取温度 void DS18B20_Start(void); //开始温度转换 void DS18B20_Write_Byte(u8 dat);//写入一个字节 u8 DS18B20_Read_Byte(void); //读出一个字节 u8 DS18B20_Read_Bit(void); //读出一个位 u8 DS18B20_Check(void); //检测是否存在DS18B20 void DS18B20_Reset(void); //复位DS18B20 #endif// #include lcd1602.h // IO初始化 void lcd1602_gpio_init(void) { GPIO_InitTypeDef gpio_cfg; RCC_APB2PeriphClockCmd(LCD_CTRL_RCC, ENABLE); // 控制脚 PB0 PB1 PB2 推挽输出 gpio_cfg.GPIO_Pin LCD_E_PIN | LCD_RS_PIN | LCD_RW_PIN; gpio_cfg.GPIO_Mode GPIO_Mode_Out_PP; gpio_cfg.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(LCD_CTRL_PORT, gpio_cfg); // 数据脚 PB8~PB15 推挽输出 gpio_cfg.GPIO_Pin LCD_DATA_MASK; gpio_cfg.GPIO_Mode GPIO_Mode_Out_PP; gpio_cfg.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(LCD_DATA_PORT, gpio_cfg); LCD_RS_L(); LCD_RW_L(); LCD_E_L(); } // 将8位数据输出到PB8~PB15D0→PB8D7→PB15 static void lcd_set_dataport(uint8_t val) { // 先清除PB8~PB15 LCD_DATA_PORT-ODR ~(0xFF 8); // val低8位移到PB8~PB15输出 LCD_DATA_PORT-ODR | ((uint16_t)val 8); } // 写命令 #if (LCD1602_4OR8_DATA_INTERFACE 0) void lcd1602_write_cmd(uint8_t cmd) { LCD_RS_L(); LCD_RW_L(); LCD_E_L(); lcd_set_dataport(cmd); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); } #else void lcd1602_write_cmd(uint8_t cmd) { LCD_RS_L(); LCD_RW_L(); LCD_E_L(); lcd_set_dataport(cmd 4); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); lcd_set_dataport(cmd 0x0F); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); } #endif // 写数据 #if (LCD1602_4OR8_DATA_INTERFACE 0) void lcd1602_write_data(uint8_t dat) { LCD_RS_H(); LCD_RW_L(); LCD_E_L(); lcd_set_dataport(dat); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); } #else void lcd1602_write_data(uint8_t dat) { LCD_RS_H(); LCD_RW_L(); LCD_E_L(); lcd_set_dataport(dat 4); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); lcd_set_dataport(dat 0x0F); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); } #endif // LCD初始化 #if (LCD1602_4OR8_DATA_INTERFACE 0) void lcd1602_init(void) { lcd1602_gpio_init(); delay_ms(20); lcd1602_write_cmd(0x38); lcd1602_write_cmd(0x0C); lcd1602_write_cmd(0x06); lcd1602_write_cmd(0x01); } #else void lcd1602_init(void) { lcd1602_gpio_init(); delay_ms(20); lcd1602_write_cmd(0x28); lcd1602_write_cmd(0x0C); lcd1602_write_cmd(0x06); lcd1602_write_cmd(0x01); } #endif // 清屏 void lcd1602_clear(void) { lcd1602_write_cmd(0x01); } // 显示字符串 x:0~15 y:0/1 void lcd1602_show_string(uint8_t x, uint8_t y, uint8_t *str) { uint8_t i 0; if(y 1 || x 15) return; if(y 0) { while(*str ! \0) { if(i 16 - x) lcd1602_write_cmd(0x80 i x); else lcd1602_write_cmd(0x80 0x40 i x - 16); lcd1602_write_data(*str); str; i; } } else { while(*str ! \0) { if(i 16 - x) lcd1602_write_cmd(0x80 0x40 i x); else lcd1602_write_cmd(0x80 i x - 16); lcd1602_write_data(*str); str; i; } } } #ifndef _LCD1602_H #define _LCD1602_H #include stm32f10x.h #include SysTick.h // 08位并口 14位并口 #define LCD1602_4OR8_DATA_INTERFACE 0 // 控制引脚映射 #define LCD_RS_PIN GPIO_Pin_1 #define LCD_RW_PIN GPIO_Pin_2 #define LCD_E_PIN GPIO_Pin_0 #define LCD_CTRL_PORT GPIOB #define LCD_CTRL_RCC RCC_APB2Periph_GPIOB // 数据引脚 PB8~PB15 对应D0~D7 #define LCD_DATA_MASK GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15 #define LCD_DATA_PORT GPIOB #define LCD_DATA_RCC RCC_APB2Periph_GPIOB // 控制电平宏 #define LCD_RS_H() GPIO_SetBits(LCD_CTRL_PORT, LCD_RS_PIN) #define LCD_RS_L() GPIO_ResetBits(LCD_CTRL_PORT, LCD_RS_PIN) #define LCD_RW_H() GPIO_SetBits(LCD_CTRL_PORT, LCD_RW_PIN) #define LCD_RW_L() GPIO_ResetBits(LCD_CTRL_PORT, LCD_RW_PIN) #define LCD_E_H() GPIO_SetBits(LCD_CTRL_PORT, LCD_E_PIN) #define LCD_E_L() GPIO_ResetBits(LCD_CTRL_PORT, LCD_E_PIN) // 函数声明 void lcd1602_gpio_init(void); void lcd1602_write_cmd(uint8_t cmd); void lcd1602_write_data(uint8_t dat); void lcd1602_init(void); void lcd1602_clear(void); void lcd1602_show_string(uint8_t x, uint8_t y, uint8_t *str); #endif//SysTick.c #include SysTick.h static u8 fac_us0; //us延时倍乘数 static u16 fac_ms0; //ms延时倍乘数 //初始化延迟函数 //SYSTICK的时钟固定为AHB时钟的1/8 //SYSCLK:系统时钟频率 void SysTick_Init(u8 SYSCLK) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); fac_usSYSCLK/8; fac_ms(u16)fac_us*1000; } //延时nus //nus为要延时的us数. void delay_us(u32 nus) { u32 temp; SysTick-LOADnus*fac_us; //时间加载 SysTick-VAL0x00; //清空计数器 SysTick-CTRL|SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { tempSysTick-CTRL; }while((temp0x01)!(temp(116))); //等待时间到达 SysTick-CTRL~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick-VAL 0X00; //清空计数器 } //延时nms //注意nms的范围 //SysTick-LOAD为24位寄存器,所以,最大延时为: //nms0xffffff*8*1000/SYSCLK //SYSCLK单位为Hz,nms单位为ms //对72M条件下,nms1864 void delay_ms(u16 nms) { u32 temp; SysTick-LOAD(u32)nms*fac_ms; //时间加载(SysTick-LOAD为24bit) SysTick-VAL 0x00; //清空计数器 SysTick-CTRL|SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { tempSysTick-CTRL; }while((temp0x01)!(temp(116))); //等待时间到达 SysTick-CTRL~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick-VAL 0X00; //清空计数器 } #ifndef _SysTick_H #define _SysTick_H #include system.h void SysTick_Init(u8 SYSCLK); void delay_ms(u16 nms); void delay_us(u32 nus); #endif