蓝桥杯单片机第九届国赛

#ifndef __DS18B20_H__
#define __DS18B20_H__

#include <mega16.h>
#include <stdint.h>

#define DQ_DDR_IN()  DDRB.5 = 0    // PB5引脚设置为输入
#define DQ_DDR_OUT() DDRB.5 = 1    // 设置为输出

#define DQ_SET()     PORTB.5 = 1   // 输出1
#define DQ_RESET()   PORTB.5 = 0   // 输出0
#define DQ_WRITE(x)  PORTB.5 = (x) // 输出x

#define DQ_DATA      PINB.5        // 读取端口

uint8_t ds18b20_init(void);
uint16_t read_temperature(void);
void read_temp_init(void);

#endif
#include <delay.h>

#include "ds18b20.h"

// 初始化DS18B20传感器
uint8_t ds18b20_init(void) {
    uint8_t is_high = 0;

    // 设置DQ引脚为输出
    DQ_DDR_OUT();
    
    // 发送复位脉冲
    DQ_SET();
    delay_us(5);
    DQ_RESET();
    delay_us(500);
    DQ_SET();
    
    // 切换DQ引脚为输入
    DQ_DDR_IN();
    
    // 等待DS18B20的响应
    delay_us(70);
    is_high = DQ_DATA;
    delay_us(500);
    
    return is_high;
}

// 向DS18B20写入一个字节的数据
void write_ds18b20(uint8_t value) {
    uint8_t i;
    DQ_DDR_OUT();

    for (i = 0; i < 8; i++) {
        // 发送写时序
        DQ_RESET();
        delay_us(10);

        // 写入数据位
        DQ_WRITE((value & (1 << i)) > 0);

        delay_us(60);
        DQ_SET();
        delay_us(10);
    }
}

// 从DS18B20读取一个字节的数据
uint8_t read_ds18b20(void) {
    uint8_t i;
    uint8_t value = 0;

    for (i = 0; i < 8; i++) {
        // 发送读时序
        DQ_DDR_OUT();
        DQ_RESET();
        delay_us(5);
        DQ_SET();
        delay_us(5);

        // 切换DQ引脚为输入
        DQ_DDR_IN();

        // 读取数据位
        value |= (DQ_DATA << i);

        delay_us(70);
    }

    return value;
}

// 读取DS18B20传感器的温度值
uint16_t read_temperature(void) {
    uint8_t data_h, data_l;

    // 关中断
    #asm("cli")
    
    // 初始化DS18B20传感器
    while (ds18b20_init()) {};
    
    // 发送跳过ROM命令
    write_ds18b20(0xCC);
    
    // 发送温度转换命令
    write_ds18b20(0x44);
    
    // 初始化DS18B20传感器
    while (ds18b20_init()) {};

    // 发送跳过ROM命令
    write_ds18b20(0xCC);
    
    // 发送读取温度命令
    write_ds18b20(0xBE);
    
    // 读取温度数据低字节
    data_l = read_ds18b20();
    
    // 读取温度数据高字节
    data_h = read_ds18b20();
    
    // 开中断
    #asm("sei")

    // 计算温度值并返回
    return ((data_h & 0x0F) << 4 | (data_l >> 4)) * 100 + (data_l & 0x0F) * 625 / 100;
}

void read_temp_init(void) {
    #asm("cli")
    
    // 初始化DS18B20传感器
    ds18b20_init();
    
    // 发送跳过ROM命令
    write_ds18b20(0xCC);
    
    // 发送温度转换命令
    write_ds18b20(0x44);

    // 开中断
    #asm("sei")

    delay_ms(800);
}
#ifndef __SHOW_SEG_H
#define __SHOW_SEG_H

#include <mega16.h>
#include <stdint.h>

#define SEG_PORT PORTA //IO口宏定义
#define SEG_DDR DDRA
#define SEG_NUM 8
#define SEG_MAX_NUM 8
#define LE_PORT_BIT PORTD.0
#define LE_PORT_DDR DDRD.0
#define SEG_U 16
#define SEG_F 15
#define SEG_C 12
#define SEG_H 18
#define SEG_P 19
#define SEG_BAR 17
void seg_init(void);
void seg_show(void);
extern uint8_t seg_en[SEG_NUM];
extern uint8_t seg_num[SEG_NUM];
extern uint8_t seg_point[SEG_NUM];

#endif
#include <mega16.h>
#include <stdint.h>
#include <delay.h>
#include "show_seg.h"
//段码  0,1,2,3,4,5,6,7,8,9,A,b,C,d,E,F,U,-,H,P
flash char seg_code[20] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x3E, 0x40, 0x76, 0x73};
uint8_t seg_en[SEG_NUM];    //数码管使能标志位
uint8_t seg_num[SEG_NUM];   //存放每个数码管要显示的东西
uint8_t seg_point[SEG_NUM]; //数码管小数点显示使能标志位
uint8_t seg_flag;   

//数码管初始化函数,默认数码管全部关闭
void seg_init(void) {
    SEG_DDR = 0xFF;
    SEG_PORT = 0x00;
    
    LE_PORT_DDR = 0x01;

    LE_PORT_BIT = 0x01; 
    LE_PORT_BIT = 0x00;
}

void seg_show(void) {
    SEG_PORT = 0;   //数码管显示全部清零
    LE_PORT_BIT = 0x01;
    LE_PORT_BIT = 0x00;

    SEG_PORT = ~(seg_en[seg_flag] << seg_flag); //给每一位数码管传入使能数据
    LE_PORT_BIT = 0x01; //锁存器使能
    LE_PORT_BIT = 0x00;
    // SEG_PORT = 0;
    SEG_PORT = seg_code[seg_num[seg_flag]] | (seg_point[seg_flag] << 7);//传入段码
    seg_flag = (seg_flag + 1) % 8;
}
#ifndef __EEPROM_H__
#define __EEPROM_H__

#define E_WRITE_ADDR 0xA0 // 写地址
#define E_READ_ADDR  0xA1 // 读地址

void EEPROM_write(uint8_t addr, uint8_t data);
uint8_t EEPROM_read(uint8_t addr);

#endif
#include <stdint.h>

#include "I2C.h"
#include "EEPROM.h"

// 向EEPROM写入一个字节的数据
void EEPROM_write(uint8_t addr, uint8_t data) {
    // 发送起始信号
    IIC_start();
    
    // 发送EEPROM写入地址
    IIC_write(E_WRITE_ADDR);
    IIC_read_act();
    
    // 发送EEPROM内存地址
    IIC_write(addr);
    IIC_read_act();
    
    // 发送要写入的数据
    IIC_write(data);
    IIC_read_act();
    
    // 发送停止信号
    IIC_stop();
}

// 从EEPROM读取一个字节的数据
uint8_t EEPROM_read(uint8_t addr) {
    uint8_t data = 0;
    
    // 发送起始信号
    IIC_start();
    
    // 发送EEPROM写入地址
    IIC_write(E_WRITE_ADDR);
    IIC_read_act();
    
    // 发送EEPROM内存地址
    IIC_write(addr);
    IIC_read_act();
    
    // 发送起始信号(切换到读模式)
    IIC_start();
    
    // 发送EEPROM读取地址
    IIC_write(E_READ_ADDR);
    IIC_read_act();
    
    // 读取数据
    data = IIC_read();
    
    // 发送非应答信号
    IIC_write_act(1);
    
    // 发送停止信号
    IIC_stop();
    
    return data;
}

#ifndef __I2C_H__
#define __I2C_H__
#include <stdint.h>
#include <mega16.h>
#include <delay.h>

#define SCL_DDR DDRB.3
#define SDA_DDR DDRB.4

#define SCL_PORT PORTB.3
#define SDA_PORT PORTB.4

#define SCL_PIN PINB.3
#define SDA_PIN PINB.4

#define SCL_OUT()    SCL_DDR = 1
#define SCL_IN()     SCL_DDR = 0

#define SDA_OUT()    SDA_DDR = 1
#define SDA_IN()     SDA_DDR = 0

#define SCL_SET()    SCL_PORT = 1; delay_ms(1);
#define SCL_RESET()  SCL_PORT = 0; delay_ms(1);
#define SCL_WRITE(x) SCL_PORT = (x); delay_ms(1);

#define SDA_SET()    SDA_PORT = 1; delay_ms(1);
#define SDA_RESET()  SDA_PORT = 0; delay_ms(1);
#define SDA_WRITE(x) SDA_PORT = (x); delay_ms(1);

#define SCL_DATA()   SCL_PIN
#define SDA_DATA()   SDA_PIN

void IIC_init(void);
void IIC_start(void);
void IIC_stop(void);
void IIC_write(uint8_t data);
uint8_t IIC_read(void);
void IIC_write_act(uint8_t act);
uint8_t IIC_read_act(void);

#endif
#include <stdint.h>
#include "I2C.h"

// 初始化I2C总线
void IIC_init(void) {
    SCL_OUT();
    SDA_OUT();
    SCL_SET();
    SDA_SET();
}

// 发送I2C起始信号
void IIC_start(void) {
    SDA_SET();
    SCL_SET();
    SDA_RESET();
    SCL_RESET();
}

// 发送I2C停止信号
void IIC_stop(void) {
    SDA_RESET();
    SCL_SET();
    SDA_SET();
}

// 向I2C总线写入一个字节的数据
void IIC_write(uint8_t data) {
    uint8_t i;
    for (i = 0; i < 8; i++) {
        SDA_WRITE(data & (0x80 >> i));
        SCL_SET();
        SCL_RESET();
    }
    SDA_RESET();
}

// 从I2C总线读取一个字节的数据
uint8_t IIC_read(void) {
    uint8_t i;
    uint8_t data = 0;
    
    SDA_IN();

    for (i = 0; i < 8; i++) {
        SCL_SET();
        data |= (SDA_DATA() << (7 - i));
        SCL_RESET();
    }
    SDA_OUT();
    return data;
}

// 向I2C总线写入一个动作(活动)信号
void IIC_write_act(uint8_t act) {
    SDA_WRITE(act);
    SCL_SET();
    SCL_RESET();
}

// 从I2C总线读取一个动作(活动)信号
uint8_t IIC_read_act(void) {
    uint8_t act = 0;
    SDA_SET();
    SCL_SET();
    SDA_IN();
    act = SDA_DATA();
    SDA_OUT();
    SCL_RESET();
    return act;
}
#ifndef __KEY_H__
#define __KEY_H__

#include <mega16.h>
#include <stdint.h>

#define KEY1_PORT PORTC.4   //IO口宏定义
#define KEY2_PORT PORTC.5
#define KEY3_PORT PORTC.6
#define KEY4_PORT PORTC.7
#define KEY1_PIN PINC.4
#define KEY2_PIN PINC.5
#define KEY3_PIN PINC.6
#define KEY4_PIN PINC.7
#define KEY1_DDR DDRC.4
#define KEY2_DDR DDRC.5
#define KEY3_DDR DDRC.6
#define KEY4_DDR DDRC.7

//按键名字宏定义
enum {
    KEY1, KEY2, KEY3, KEY4
};

void key_init(void);
void refresh_key(void);
uint8_t key_is_down(uint8_t key_num);
uint8_t key_is_down_long(uint8_t key_num);
#endif
#include <mega16.h>
#include <stdint.h>
#include "key.h"

uint8_t key_state[4][2];//按键状态,分为按下和断开,其中每个状态记录两次,即前一次和当前
uint8_t key_down[4];
uint8_t key_down_long[4];
#define I_KEY(x) x##_DDR = 0; \
    x##_PORT = 1;

//按键初始化函数
void key_init(void) {
    I_KEY(KEY1);//输入设为上拉模式
    I_KEY(KEY2);
    I_KEY(KEY3);
    I_KEY(KEY4);
}

//刷新按键状态,记录上一次状态同时获取当前状态,如果前一次为按下当前为松开则表示按键单击了一次
#define R_KEY(x)  key_state[x][0] = key_state[x][1]; \ 
    key_state[x][1] = !x##_PIN; \
    key_down[x] = (key_state[x][1] == 0) && (key_state[x][0] == 1);


//刷新按键状态函数
void refresh_key(void) {
    R_KEY(KEY1);
    R_KEY(KEY2);
    R_KEY(KEY3);
    R_KEY(KEY4);
}

//判断按键是否按下函数
uint8_t key_is_down(uint8_t key_num) {
    uint8_t key_value = key_down[key_num];
    key_down[key_num] = 0;
    return key_value;
}
// 按键长按
uint8_t key_is_down_long(uint8_t key_num) {
    uint8_t key_value = key_down[key_num] && (key_down_long[key_num] >= 10);
    if (key_value) {
        key_down[key_num] = 0;
        key_down_long[key_num] = 0;
    }
    return key_value;
}
#ifndef __LED_H__
#define __LED_H__

#define LED1_PORT PORTD.3
#define LED2_PORT PORTD.4
#define LED3_PORT PORTD.5
#define LED4_PORT PORTD.6
#define LED5_PORT PORTD.7
#define LED1_DDR DDRD.3
#define LED2_DDR DDRD.4
#define LED3_DDR DDRD.5
#define LED4_DDR DDRD.6
#define LED5_DDR DDRD.7

#define SET_LED(x) x##_PORT = 1
#define RESET_LED(x) x##_PORT = 0
#define WRITE_LED(x, n) x##_PORT = (n)

void led_init(void);

#endif
#include <mega16.h>
#include "led.h"

#define I_LED(x) x##_DDR = 1; \
    x##_PORT = 0;

void led_init(void) {
    I_LED(LED1);
    I_LED(LED2);
    I_LED(LED3);
    I_LED(LED4);
    I_LED(LED5);
}
#ifndef __PCF8591_H__
#define __PCF8591_H__

#define P_WRITE_ADDR 0x90 // 写地址
#define P_READ_ADDR  0x91 // 读地址

#define VOL4  0xCD // 4V
#define VOL2  0x67 // 2V
#define VOL04 0x15 // 0.4V

void write_vol(uint8_t vol);
float Pcf8591ReadVol(uint8_t channel);
#endif
#include <stdint.h>

#include "I2C.h"
#include "pcf8591.h"

// 向PCF8591写入电压值
void write_vol(uint8_t vol) {
    // 发送起始信号
    IIC_start();
    
    // 发送PCF8591写入地址
    IIC_write(P_WRITE_ADDR);
    IIC_read_act();
    
    // 发送PCF8591控制字节
    IIC_write(0x40);
    IIC_read_act();
    
    // 发送电压值
    IIC_write(vol);
    IIC_read_act();
    
    // 发送停止信号
    IIC_stop();
}
//pcf读取通道输入函数
float Pcf8591ReadVol(uint8_t channel)
{
    uint8_t num;
    float value;
    IIC_start();//发送开始信号
    IIC_write(P_WRITE_ADDR);//写入控制字节让pcf处于ad模式
    IIC_write(0x40 | channel);
    IIC_stop();
    IIC_start();
    IIC_write(P_READ_ADDR);      //发送读地址
    num=IIC_read();          //读取数据
    IIC_stop();                  //结束总线
    
    value = num * 0.01953;  //读取到的值为0-255,除51才是实际的值
    return value;
}

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值