#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#define uint unsigned int
#define uchar unsigned char
#define DASE 60000
// 定义 LM016L 引脚
sbit RS = P2^7;
sbit RW = P2^6;
sbit EN = P2^5;
// 定义 DS18B20 引脚
sbit DQ = P1^0;
// 定义心率引脚
sbit SCL = P3^3;
sbit SDA = P3^4;
sbit INT = P3^2;
// 定义MAX30102的I2C地址
#define MAX30102_ADDR 0xAE
// 定义蜂鸣器引脚
#define LCD_DATA P0
//定义蜂鸣器引脚
sbit BUZZER = P3^6;
// 函数声明
void delay_us(unsigned int us);
void delay_ms(unsigned int ms);
void lcd_init();
void lcd_command(unsigned char cmd);
void lcd_data(unsigned char dat);
void lcd_string(const char *str);
void display_heart_rate(unsigned int heart_rate);
void display_temperature(float temperature);
// DS18B20 相关函数声明
bit ds18b20_reset(void);
void ds18b20_write_byte(unsigned char dat);
unsigned char ds18b20_read_byte(void);
float ds18b20_read_temp(void);
uint D_num; // 定时器中断计数变量
// 声明 str 数组为全局变量
static unsigned char str[10];
// 全局变量用于心率计算
unsigned int pulse_count = 0;
unsigned int prev_pulse_count = 0;
unsigned int heart_rate = 0;
uint temp; // 临时变量
uint count; // 计数
float tempF;
bit flag_S = 0;
bit flag_1s = 0;
unsigned int one_second_count = 0;
// 新增变量用于蜂鸣器控制
bit buzzer_alarm = 0; // 蜂鸣器报警标志
// 定时器0初始化函数
void InitTimer0(void)
{
TMOD = 0x01;
TH0 = 0xFC;
TL0 = 0x18;
EA = 1;
ET0 = 1;
TR0 = 1;
}
void delay_ms(unsigned int ms) // @12MHz
{
unsigned i, j;
for (i = ms; i > 0; i--)
for (j = 120; j > 0; j--);
}
// 初始化 LCD
void lcd_init()
{
delay_ms(15);
lcd_command(0x38); // 设置 16x2 显示,5x7 点阵,8 位数据
delay_ms(5);
lcd_command(0x38);
delay_ms(5);
lcd_command(0x38);
lcd_command(0x0C); // 打开显示,关闭光标
lcd_command(0x06); // 光标右移,字符不移动
lcd_command(0x01); // 清屏
delay_ms(5);
}
// 发送 LCD 命令
void lcd_command(unsigned char cmd)
{
RS = 0;
RW = 0;
LCD_DATA = cmd;
delay_ms(1);
EN = 1;
_nop_();
EN = 0;
}
// 发送 LCD 数据
void lcd_data(unsigned char dat)
{
RS = 1;
RW = 0;
LCD_DATA = dat;
delay_ms(1);
EN = 1;
_nop_();
EN = 0;
}
// 发送字符串到 LCD
void lcd_string(const char *str)
{
while (*str)
{
lcd_data(*str++);
}
}
// 微秒级延时函数
void delay(uint t) // @12T 1us
{
while (t--);
}
// I2C起始信号
void I2C_Start() {
SDA = 1;
SCL = 1;
delay(1);
SDA = 0;
delay(1);
SCL = 0;
}
// I2C停止信号
void I2C_Stop() {
SDA = 0;
SCL = 1;
delay(1);
SDA = 1;
delay(1);
}
// I2C发送一个字节
void I2C_SendByte(unsigned char dat) {
unsigned char i;
for (i = 0; i < 8; i++) {
SDA = (dat & 0x80) >> 7;
dat <<= 1;
SCL = 1;
delay(1);
SCL = 0;
delay(1);
}
}
// I2C接收一个字节
unsigned char I2C_ReceiveByte() {
unsigned char i, dat = 0;
SDA = 1;
for (i = 0; i < 8; i++) {
SCL = 1;
dat <<= 1;
if (SDA) dat |= 0x01;
SCL = 0;
delay(1);
}
return dat;
}
// I2C发送应答信号
void I2C_SendAck(bit ack) {
SDA = ack;
SCL = 1;
delay(1);
SCL = 0;
delay(1);
}
// I2C接收应答信号
bit I2C_ReceiveAck() {
bit ack;
SDA = 1;
SCL = 1;
ack = SDA;
SCL = 0;
delay(1);
return ack;
}
// 向MAX30102写一个字节数据
void MAX30102_WriteByte(unsigned char reg, unsigned char dat) {
I2C_Start();
I2C_SendByte(MAX30102_ADDR & 0xFE); // 写地址
I2C_ReceiveAck();
I2C_SendByte(reg);
I2C_ReceiveAck();
I2C_SendByte(dat);
I2C_ReceiveAck();
I2C_Stop();
}
// 从MAX30102读一个字节数据
unsigned char MAX30102_ReadByte(unsigned char reg) {
unsigned char dat;
I2C_Start();
I2C_SendByte(MAX30102_ADDR & 0xFE); // 写地址
I2C_ReceiveAck();
I2C_SendByte(reg);
I2C_ReceiveAck();
I2C_Start();
I2C_SendByte(MAX30102_ADDR | 0x01); // 读地址
I2C_ReceiveAck();
dat = I2C_ReceiveByte();
I2C_SendAck(1); // 非应答
I2C_Stop();
return dat;
}
// 初始化MAX30102
void MAX30102_Init() {
MAX30102_WriteByte(0x09, 0x03); // 配置采样率等
MAX30102_WriteByte(0x0A, 0x27); // 配置LED等
MAX30102_WriteByte(0x0C, 0x00); // FIFO_WR_PTR = 0
MAX30102_WriteByte(0x0D, 0x00); // FIFO_OVF_CTR = 0
MAX30102_WriteByte(0x0E, 0x00); // FIFO_RD_PTR = 0
}
// 显示心率
void display_heart_rate(unsigned int heart_rate)
{
lcd_command(0x87); // 设置显示位置
sprintf(str, "%d bpm ", heart_rate);
lcd_string(str);
}
// 显示温度
void display_temperature(float temperature)
{
lcd_command(0xC7); // 设置显示位置
if (temperature == -1)
{
sprintf(str, "Err");
}
else
{
temperature += 4.2;
sprintf(str, "%.1f C", temperature);
}
lcd_string((const char *)str);
}
void Init_DS18b20() // 18b20初始化函数
{
DQ = 1; // DQ复位
delay(8);
DQ = 0; // 释放DQ
delay(80); // DS18B20收到信号后延时
DQ = 1; // 读取DQ
delay(30);
}
void write_byte(uchar dat) // 写时序
{
uchar i = 0;
for (i = 8; i > 0; i--)
{
DQ = 0;
DQ = dat & 0x01; // 写1,在15微秒内拉低
delay(5); // 写0,拉低60微秒
DQ = 1;
dat >>= 1;
}
delay(4);
}
uchar read_byte() // 读时序
{
uchar i = 0;
uchar dat = 0;
for (i = 8; i > 0; i--)
{
DQ = 0; // 拉低ds18b20单总线
dat >>= 1;
DQ = 1; // 15微秒内拉释放总线
if (DQ)
dat |= 0x80;
delay(4);
}
return (dat);
}
float ds18b20_read_temp(void)
{
Init_DS18b20(); // 初始化18b20
write_byte(0xcc); // 跳过读写序列号
write_byte(0x44); // 启动温度转换
Init_DS18b20(); // 初始化18b20
write_byte(0xCC); // 跳过读写序列号
write_byte(0xBE); // 读温度寄存器
temp = read_byte(); // 读取温度低8位
temp = read_byte() << 8 | temp; // 读取温度高8位
tempF = temp * 0.0625;
return tempF;
}
void Timer0Interrupt() interrupt 1
{
static uint i;
TH0 = 0xFC;
TL0 = 0x18;
count++;
i++;
one_second_count++;
if (i >= 500) // 0.5秒
{
i = 0;
flag_S = 1; // 0.5秒标志
}
if (one_second_count >= 1000) // 1秒
{
one_second_count = 0;
flag_1s = 1;
}
}
// 外部中断 0 服务函数,用于检测心率脉冲
void External0_ISR() interrupt 0
{
static uint last_time = 0;
uint current_time = count;
if (current_time - last_time > 20) // 消抖处理,20ms
{
pulse_count++;
last_time = current_time;
}
}
// 主程序
void main()
{
float temperature = 0.0;
unsigned int time_count = 0;
// 初始化 LCD
lcd_init();
lcd_string("Heart: ");
lcd_command(0xC0); // 第二行
lcd_string("Temp: ");
InitTimer0();
// 初始化外部中断 0
IT0 = 1; // 下降沿触发
EX0 = 1; // 使能外部中断 0
EA = 1; // 使能全局中断
IE0 = 0; // INT0中断请求标志清0
while (1)
{
if (flag_S) // 0.5秒
{
flag_S = 0;
// 获取温度
temperature = ds18b20_read_temp();
temperature += 4.2;
display_temperature(temperature);
// 温度报警检查
if (temperature < 30.8 || temperature > 35.8)
{
buzzer_alarm = 1;
if (count % 2 == 0) { // 以1秒为周期闪烁鸣叫
BUZZER = 0;
} else {
BUZZER = 1;
}
}
else
{
buzzer_alarm = 0;
BUZZER = 1;
}
}
if (flag_1s) // 1秒
{
flag_1s = 0;
heart_rate = pulse_count * 60; // 计算心率
display_heart_rate(heart_rate);
pulse_count = 0; // 清零脉冲计数
}
}
}
|