蓝桥杯单片机模板(自用)——基于柳离风模板

蓝桥杯单片机模板(自用)——基于柳离风模板

一、工程结构

在这里插入图片描述

二、USER文件夹

main.c

存放main函数,按键任务,采集任务,显示任务,主逻辑等。
main.c

#include <STC15F2K60S2.H>
#include "sys.h"
#include "display.h"
#include "key.h"
#include "timer.h"
#include "ds1302.h"
#include "iic.h"
#include "onewire.h"
#include "uart.h"
#include "ultrasound.h"

/* 变量区 */
uchar SMG[8] = {20,20,20,20,20,20,20,20};   //数码管显示
uchar dot[8] = {0,0,0,0,0,0,0,0};           //小数点显示
uchar LED[8] = {0,0,0,0,0,0,0,0};           //led显示
uint temperature;                           //温度变量
uchar state_display = 5;                    //显示状态
bit state_led;

/* 函数区 */
//显示任务
void display_task(void)
{
    /*LED任务*/
    LED[0] = state_led;//放在延迟判断前,这样闪烁间隔才正常
    LED[1] = 1;
    LED[2] = 0;
    LED[3] = 1;
    LED[4] = 0;
    LED[5] = 1;
    LED[6] = 0;
    LED[7] = 1;
    
    if(display_dly<100)return;
    display_dly = 0;
    
    /*数码管任务*/
    switch(state_display)
    {
        case 0:    /*频率显示*/
            SMG[0] = 15;
            SMG[1] = 20;
            SMG[2] = 20;
            SMG[3] = (fre<10000) ? 20:fre/10000;
            SMG[4] = (fre<1000) ? 20:fre/1000%10;
            SMG[5] = (fre<100) ? 20:fre/100%10;
            SMG[6] = (fre<10) ? 20:fre/10%10;
            SMG[7] = fre%10;
            break;
    }
}

//采集任务
void collect_task(void)
{
    if(collect_dly<300)return;
    collect_dly = 0;
    
    temperature = ds18b20_read(0);
//     printf("温度是:%d°C\r\n",(uint)temperature);

    
}

//按键处理任务
void key_task(void)
{
    uchar key_num;
    if(key_dly<10)return;
    key_dly = 0;
//    key_num = key_scan1();
    key_num = key_scan2();
    switch (key_num)
    {
        /* 独立按键 */
//        case 4:
//            break;
//        case 5:
//            break;
//        case 6:  state_relay = ~state_relay;
//            break;
//        case 7:  state_beep = ~state_beep;
//            break;
        
        /* 矩阵键盘 */
        case 4:  
            break;
        case 5:  
            break;
        case 8:  state_relay = ~state_relay;
            break;
        case 9:  state_led = ~state_led;
            break;
    }
}

void main(void)
{
    sys_init();                 //系统初始化-关闭蜂鸣器继电器
    Timer0_Init();              //定时器0-计数模式初始化
    Timer1_Init();              //定时器1-1ms中断任务调度初始化
//    Uart1_Init();               //串口1初始化9600波特率,与矩阵键盘几个引脚冲突
    ds1302_write();             //ds1302时钟初始化-写入时间
    ds18b20_read(0);             //ds18b20初始化-上电默认85度,先读一下,延时750ms,再读一下
//    delay_ms(750);
//    temperature = ds18b20_read(0);
    AT24C02_write(1,123);       //EEPROM初始化-写入值
    EA = 1;                     //打开总中断
    while(1)
    {
        key_task();
        collect_task();
        display_task();
    }
}

三、BSP文件夹

1、sys

存放系统初始化函数和公用函数、定义等,包括hc573锁存器操作、上电关闭蜂鸣器继电器函数、延时函数、顶层头文件和宏定义等。
sys.c

#include "sys.h"

/**
 * @brief 实现led,继电器蜂鸣器,数码管通道的选择
 * 
 * @param channel 4:led,5:继电器蜂鸣器,6:位选,7:段选
 */
void hc573(uchar channel)
{
    switch(channel)
    {
        case 4: P2 = P2 & 0x1f | 0x80;break;
        case 5: P2 = P2 & 0x1f | 0xa0;break;
        case 6: P2 = P2 & 0x1f | 0xc0;break;
        case 7: P2 = P2 & 0x1f | 0xe0;break;
    }
    P2 = P2 & 0x1f;
}


/**
* @brief 系统初始化,关闭led、蜂鸣器继电器,交换位置解决数码管上电闪烁的问题
 * 
 */
void sys_init(void)
{
    P0 = 0xff;
    hc573(4);
    P0 = 0x00;
    hc573(5);

}

/**
 * @brief ms级延时
 * 
 * @param xms 延时ms数
 */
void delay_ms(uint xms) //@12.000MHz
{
    unsigned char data i, j;
    while(xms--)
    {
        i = 12;
        j = 169;
        do
        {
            while (--j);
        } while (--i);
    }
    
}

/**
 * @brief us级延时
 * 
 * @param xus 延时us数
 */
void delay_us(uint xus) //@12.000MHz
{
    while(xus--)
    {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    }
}


sys.h

#ifndef __SYS_H
#define __SYS_H

#include <STC15F2K60S2.H>
#include "intrins.h"
#include "stdio.h"


#define uchar unsigned char
#define uint unsigned int

void hc573(uchar channel);
void sys_init(void);
void delay_ms(uint xms);
void delay_us(uint xus);

#endif

2、display

存放显示驱动函数,包括LED,数码管,继电器,蜂鸣器等外设的控制。
display.c

#include "display.h"

uchar uln2003 = 0x00;//蜂鸣器继电器对应锁存器当前状态
// 共阳数码管段码表
code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A10
0x83, //b11
0xc6, //C12
0xa1, //d13
0x86, //E14
0x8e, //F15
0x89, //H16
0x8c, //P17
0xc7, //L18
0xbf, //-19
0xff  //灭20
};


/**
 * @brief led显示
 * 
 * @param LED led数组首地址
 * @param pos 数组索引
 */
void led(uchar * LED,uchar pos)
{
    static uchar temp = 0xff;
    if(LED[pos])
        temp &= ~(0x01 << pos);
    else 
        temp |= 0x01 << pos;
    P0 = temp;
    hc573(4);
}


/**
 * @brief 数码管显示
 * 
 * @param SMG 数码管数组首地址
 * @param dot 小数点数组首地址
 * @param pos 数组索引
 */
void smg(uchar * SMG,uchar * dot,uchar pos)
{
    P0 = 0xff;              //消隐
    hc573(7);
    P0 = 0x01 << pos;       //位选
    hc573(6);
    if(dot[pos])            //段选
        P0 = Seg_Table[SMG[pos]] & 0x7f;
    else
        P0 = Seg_Table[SMG[pos]];
    hc573(7);
}


/**
 * @brief 继电器控制
 * 
 * @param state_relay 0关1开
 */
void relay(uchar state_relay)
{
    if(state_relay)
        uln2003 |= 0x10;
    else
        uln2003 &= ~0x10;
    P0 = uln2003;
    hc573(5);
}


/**
 * @brief 蜂鸣器控制
 * 
 * @param state_beep 0关1开
 */
void beep(uchar state_beep)
{
    if(state_beep)
        uln2003 |= 0x40;
    else
        uln2003 &= ~0x40;
    P0 = uln2003;
    hc573(5);
}




display.h

#ifndef __DISPLAY_H
#define __DISPLAY_H

#include "sys.h"

void led(uchar * LED,uchar pos);
void smg(uchar * temp,uchar * dot,uchar pos);
void relay(uchar state_relay);
void beep(uchar state_beep);

#endif

3、key

存放按键扫描函数,包括独立按键和矩阵键盘,这里返回值为按键在开发板上的元件位号,使用时注意和串口,NE555冲突的引脚。
key.c

#include "key.h"


/**
 * @brief 独立按键扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan1(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    if((key_up == 1) && (P30 == 0 || P31 == 0 || P32 == 0 || P33 == 0))
    {
        key_up = 0;
        if(P30 == 0)          key = 7;
        else if(P31 == 0)     key = 6;
        else if(P32 == 0)     key = 5;
        else if(P33 == 0)     key = 4;
        return key;
    }
    else if(P30 == 1 && P31 == 1 && P32 == 1 && P33 == 1)
        key_up = 1;
    return 0;
}


/**
 * @brief 矩阵键盘扫描函数
 * 
 * @return uchar 键值对应的元件位号
 */
uchar key_scan2(void)
{
    uchar key = 0;                      //按键值
    static bit key_up = 1;              //按键松开标志,1松开0按下
    P44 = P42 = 1;                      //列扫描
    P32 = P33 = 0;
    if((key_up == 1)&&(P44 == 0 || P42 == 0))
    {
        
        if(P44 == 0)        key = 7;
        else if(P42 == 0)   key = 11;
        else                return 0;
        key_up = 0;                     //标志按下
        P44 = P42 = 0;
        P32 = P33 = 1;                  //行扫描
        if(P32 == 0)   key = key - 2;
        else if(P33 == 0)   key = key - 3;
        return key;
    }
    else if(P44 == 1 && P42 == 1)
        key_up = 1;                     //松开
    return 0;
}


key.h

#ifndef __KEY_H
#define __KEY_H

#include "sys.h"


uchar key_scan1(void);
uchar key_scan2(void);

#endif

4、timer

存放定时器初始化和中断函数,包括定时器0测NE555频率、定时器1中断1ms任务调度,使用时注意与main.c的全局变量声明。
timer.c

#include "timer.h"


unsigned long systick_ms;       //滴答定时器
uchar key_dly;                  //按键任务调度
uint display_dly;               //显示任务调度
uint collect_dly;               //采集任务调度
uchar pos;                      //数码管led扫描位置
uint count_1s;                  //1s计时测频率
uint fre;                       //频率
bit state_relay;                //继电器状态
bit state_beep;                 //蜂鸣器状态


void Timer0_Init(void)      //计数模式测方波频率@12.000MHz
{
    AUXR &= 0x7F;           //定时器时钟12T模式
    TMOD &= 0xF0;           //设置定时器模式
    TMOD |= 0x05;           //设为计数模式
    TL0 = 0;                //设置定时初始值
    TH0 = 0;                //设置定时初始值
    TF0 = 0;                //清除TF0标志
    TR0 = 1;                //定时器0开始计时
}


void Timer1_Init(void)      //1毫秒@12.000MHz
{
    AUXR &= 0xBF;           //定时器时钟12T模式
    TMOD &= 0x0F;           //设置定时器模式
    TL1 = 0x18;             //设置定时初始值
    TH1 = 0xFC;             //设置定时初始值
    TF1 = 0;                //清除TF1标志
    TR1 = 1;                //定时器1开始计时
    ET1 = 1;                //开启定时器1中断
//    EA = 1;                 //开启总中断
}


void TIMER1_IRQHandler(void)    interrupt 3
{
    /* 任务调度处理 */
    systick_ms++;
    key_dly++;
    display_dly++;
    collect_dly++;
    
    /* 测频率 */
    if(++count_1s == 1000)
    {
        fre = (TH0 << 8) | TL0;
        TH0 = 0;
        TL0 = 0;
        count_1s = 0;
    }

    /* 显示处理 */
    smg(SMG,dot,pos);
    led(LED,pos);
    if(++pos == 8)  pos = 0;
    relay(state_relay);
    beep(state_beep);
}

timer.h

#ifndef __TIMER_H
#define __TIMER_H

#include "sys.h"
#include "display.h"

extern unsigned long systick_ms;       //滴答定时器
extern uchar key_dly;                  //按键任务调度
extern uint display_dly;               //显示任务调度
extern uint collect_dly;               //采集任务调度
extern uchar pos;                      //数码管led扫描位置
extern uint count_1s;                  //1s计时测频率
extern uint fre;                       //频率
extern bit state_relay;                //继电器状态
extern bit state_beep;                 //蜂鸣器状态


extern uchar SMG[];
extern uchar dot[];
extern uchar LED[];

void Timer0_Init(void);
void Timer1_Init(void);

#endif

5、iic

存放iic驱动函数,包括AT24C02、PCF8591的读写操作,使用时注意PCF8591读到的结果是上一次转换的值,多通道时要连续读两次。在进行ADC线性转换时,表达式中乘除相关的常量加个.0变成浮点型,否则整数相除可能四舍五入为0,如51.0/adc,而51/adc当51小于adc时,结果可能恒为0。AT24C02页写时while里每写一个字节加个I2C_Delay(200);连续写时要加10ms左右延时
iic.c

/*  #   I2C代码片段说明
    1.  本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
    2.  参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
        中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include "iic.h"

#define DELAY_TIME  10

sbit scl = P2^0;        //时钟线
sbit sda = P2^1;        //数据线


//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();        
    }
    while(n--);         
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
    I2C_Delay(DELAY_TIME);
    sda = 0;
    I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
    I2C_Delay(DELAY_TIME);
    sda = 1;
    I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
    
    for(i=0; i<8; i++){
        scl = 0;
        I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
        I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
        I2C_Delay(DELAY_TIME);
    }
    
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
    unsigned char da;
    unsigned char i;
    for(i=0;i<8;i++){   
        scl = 1;
        I2C_Delay(DELAY_TIME);
        da <<= 1;
        if(sda) 
            da |= 0x01;
        scl = 0;
        I2C_Delay(DELAY_TIME);
    }
    return da;    
}

//
unsigned char I2CWaitAck(void)
{
    unsigned char ackbit;
    
    scl = 1;
    I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
    I2C_Delay(DELAY_TIME);
    
    return ackbit;
}

//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
    I2C_Delay(DELAY_TIME);
    scl = 1;
    I2C_Delay(DELAY_TIME);
    scl = 0; 
    sda = 1;
    I2C_Delay(DELAY_TIME);
}

/**
 * @brief AT24C02读一个字节
 * 
 * @param addr 地址
 * @return uchar 数据
 */
uchar AT24C02_read(uchar addr)
{
    uchar dat;
    I2CStart();                 //起始信号
    I2CSendByte(0xa0);          //发送器件地址(写)
    I2CWaitAck();               //等待应答
    I2CSendByte(addr);          //发送通道地址
    I2CWaitAck();               //等待应答

    I2CStart();                 //起始信号
    I2CSendByte(0xa1);          //发送器件地址(读)
    I2CWaitAck();               //等待应答
    dat = I2CReceiveByte();     //读数据
    I2CSendAck(1);              //不应答
    I2CStop();                  //停止信号
    return dat;
}


/**
 * @brief AT24C02页读,读取一页
 * 
 * @param buf 接收数据数组首地址
 * @param addr 内存地址,必须是8的整数倍,可以写十进制
 * @param num 数据个数
 */
void AT24C02_read_page(uchar * buf,uchar addr,uchar num)
{
    I2CStart();                 //起始信号
    I2CSendByte(0xa0);          //发送器件地址(写)
    I2CWaitAck();               //等待应答
    I2CSendByte(addr);          //发送通道地址
    I2CWaitAck();               //等待应答

    I2CStart();                 //起始信号
    I2CSendByte(0xa1);          //发送器件地址(读)
    I2CWaitAck();               //等待应答
    while(num--)
    {
        *buf++ = I2CReceiveByte();//接收数据
        if(num)
            I2CSendAck(0);      //应答
        else
            I2CSendAck(1);      //不应答
    }
    I2CStop();
}


/**
 * @brief AT24C02写入一个字节
 * 
 * @param addr 地址
 * @param dat 数据
 */
void AT24C02_write(uchar addr,uchar dat)
{
    I2CStart();                 //起始信号
    I2CSendByte(0xa0);          //发送器件地址(写)
    I2CWaitAck();               //等待应答
    I2CSendByte(addr);          //发送通道地址
    I2CWaitAck();               //等待应答

    I2CSendByte(dat);           //发送数据
    I2CWaitAck();               //等待应答
    I2CStop();                  //停止信号
}


/**
 * @brief AT24C02页写,写入一页数据
 * 
 * @param buf 数据数组首地址
 * @param addr 内存地址,必须是8的整数倍,可以写十进制
 * @param num 数据个数
 */
void AT24C02_write_page(uchar * buf,uchar addr,uchar num)
{
    I2CStart();                 //起始信号
    I2CSendByte(0xa0);          //发送器件地址(写)
    I2CWaitAck();               //等待应答
    I2CSendByte(addr);          //发送通道地址
    I2CWaitAck();               //等待应答

    while(num--)
    {
        I2CSendByte(*buf++);    //发送数据
        I2CWaitAck();           //等待应答
    }
    I2CStop();                  //停止信号
}


/**
 * @brief PCF8591读AD
 * 
 * @param control 0x00:AIN0,0x01:光敏,0x03:电位器
 * @return uchar adc量化值,读到的是上次转换的值,读两个外设时要连续读两次
 */
uchar PCF8591_read(uchar control)
{
    uchar dat;
    I2CStart();                 //起始信号
    I2CSendByte(0x90);          //发送器件地址(写)
    I2CWaitAck();               //等待应答
    I2CSendByte(control);       //发送通道地址
    I2CWaitAck();               //等待应答

    I2CStart();                 //起始信号
    I2CSendByte(0x91);          //发送器件地址(读)
    I2CWaitAck();               //等待应答
    dat = I2CReceiveByte();     //读数据
    I2CSendAck(1);              //不应答
    I2CStop();                  //停止信号
    return dat;
}

/**
 * @brief PCF8591写DA
 * 
 * @param control 只进行DA:0x40,AD/DA同时:0x40AIN0,0x41光敏,0x43电位器
 * @param dat DA量化值,0-255对应0-5V
 */
void PCF8591_write(uchar control,uchar dat)
{
    I2CStart();                 //起始信号
    I2CSendByte(0x90);          //发送器件地址(写)
    I2CWaitAck();               //等待应答
    I2CSendByte(control);       //发送通道地址
    I2CWaitAck();               //等待应答

    I2CSendByte(dat);           //发送数据
    I2CWaitAck();               //等待应答
    I2CStop();                  //停止信号
}



iic.h

#ifndef __IIC_H
#define __IIC_H

#include "sys.h"

uchar AT24C02_read(uchar addr);
void AT24C02_read_page(uchar * buf,uchar addr,uchar num);
void AT24C02_write(uchar addr,uchar dat);
void AT24C02_write_page(uchar * buf,uchar addr,uchar num);

uchar PCF8591_read(uchar control);
void PCF8591_write(uchar control,uchar dat);

#endif


6、ds1302

存放ds1302驱动函数,包括ds1302的读写,只保留了秒分时。
ds1302.c

/*  #   DS1302代码片段说明
    1.  本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
    2.  参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
        中对单片机时钟频率的要求,进行代码调试和修改。
*/                              
#include "ds1302.h"

sbit SCK = P1^7;        //时钟线
sbit SDA = P2^3;        //数据线
sbit RST = P1^3;        //复位线

code uchar write_addr[3] = {0x80,0x82,0x84};//写地址
code uchar read_addr[3] = {0x81,0x83,0x85};//读地址
        //时间:  秒, 分, 时, 日,  月,  周, 年
uchar Time[3] = {0x00,0x00,0x09};

//
void Write_Ds1302(unsigned  char temp) 
{
    unsigned char i;
    for (i=0;i<8;i++)       
    { 
        SCK = 0;
        SDA = temp&0x01;
        temp>>=1; 
        SCK=1;
    }
}   

//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
    RST=0;  _nop_();
    SCK=0;  _nop_();
    RST=1;  _nop_();  
    Write_Ds1302(address);  
    Write_Ds1302(dat);      
    RST=0; 
}

//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
    unsigned char i,temp=0x00;
    RST=0;  _nop_();
    SCK=0;  _nop_();
    RST=1;  _nop_();
    Write_Ds1302(address);
    for (i=0;i<8;i++)   
    {       
        SCK=0;
        temp>>=1;   
        if(SDA)
        temp|=0x80; 
        SCK=1;
    } 
    RST=0;  _nop_();
    SCK=0;  _nop_();
    SCK=1;  _nop_();
    SDA=0;  _nop_();
    SDA=1;  _nop_();
    return (temp);          
}


/**
 * @brief 写日期
 * 
 */
void ds1302_write(void)
{
    uchar i;
    Write_Ds1302_Byte(0x8e,0x00);       //解除写保护
    for(i = 0;i < 3;i++)                //写数据
    {
        Write_Ds1302_Byte(write_addr[i],Time[i]);
    }
    Write_Ds1302_Byte(0x8e,0x80);       //写保护
}


/**
 * @brief 读日期
 * 
 */
void ds1302_read(void)
{
    uchar i;
    for(i = 0;i < 3;i++)
    {
        Time[i] = Read_Ds1302_Byte(read_addr[i]);
    }
}


ds1302.h

#ifndef __DS1302_H
#define __DS1302_H

#include "sys.h"

extern uchar Time[];

void ds1302_write(void);
void ds1302_read(void);

#endif


7、onewire

存放ds18b20驱动函数,包括温度的读取,如果时序被中断频繁打乱可以在时序两端加上开关总中断(EA=0,1)。
onewire.c

/*  #   单总线代码片段说明
    1.  本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
    2.  参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
        中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include "onewire.h"

sbit DQ = P1^4;     //数据线

//
void Delay_OneWire(unsigned int t)  
{
    unsigned char i;
    while(t--){
        for(i=0;i<12;i++);
    }
}

//
void Write_DS18B20(unsigned char dat)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        DQ = 0;
        DQ = dat&0x01;
        Delay_OneWire(5);
        DQ = 1;
        dat >>= 1;
    }
    Delay_OneWire(5);
}

//
unsigned char Read_DS18B20(void)
{
    unsigned char i;
    unsigned char dat;
  
    for(i=0;i<8;i++)
    {
        DQ = 0;
        dat >>= 1;
        DQ = 1;
        if(DQ)
        {
            dat |= 0x80;
        }       
        Delay_OneWire(5);
    }
    return dat;
}

//
bit init_ds18b20(void)
{
    bit initflag = 0;
    
    DQ = 1;
    Delay_OneWire(12);
    DQ = 0;
    Delay_OneWire(80);
    DQ = 1;
    Delay_OneWire(10); 
    initflag = DQ;     
    Delay_OneWire(5);
  
    return initflag;
}


/**
 * @brief ds18b20温度读取
 * 
 * @param dot 小数点位数,0:保留0位小数,1: 保留一位小数,2:保留两位小数
 * @return uint 温度值,要配合小数点位数使用
 */
uint ds18b20_read(uchar dot)
{
    uint temp;                      //温度值
    uchar tml,tmh;                  //温度值低八位,高八位

    init_ds18b20();                 //初始化
    Write_DS18B20(0xcc);            //跳过ROM
    Write_DS18B20(0x44);            //开始温度转换

    init_ds18b20();                 //初始化
    Write_DS18B20(0xcc);            //跳过ROM
    Write_DS18B20(0xbe);            //读取暂存寄存器
    
    tml = Read_DS18B20();           //读取低八位
    tmh = Read_DS18B20();           //读取高八位
    temp = (tmh << 8) | tml;        //合并数据
    switch (dot)                    //根据小数点位数设置精度
    {
        case 0: temp = temp * 0.0625;break;
        case 1: temp = temp * 0.625;break;
        case 2: temp = temp * 6.25;break;
    }
    return temp;
}

onewire.h

#ifndef __ONEWIRE_H
#define __ONEWIRE_H

#include "sys.h"

uint ds18b20_read(uchar dot);

#endif

8、uart

存放串口驱动函数,包括串口初始化、收发、中断等。
uart.c

#include "uart.h"

uchar uart_rxbuf[10];               //串口接收数组
uchar uart_rxindex;                 //串口接收数组索引


void Uart1_Init(void)   //9600bps@12.000MHz
{
    SCON = 0x50;            //8位数据,可变波特率
    AUXR |= 0x01;           //串口1选择定时器2为波特率发生器
    AUXR |= 0x04;           //定时器时钟1T模式
    T2L = 0xC7;             //设置定时初始值
    T2H = 0xFE;             //设置定时初始值
    AUXR |= 0x10;           //定时器2开始计时
    ES = 1;                 // 允许串口中断
}


void UART1_IRQHandler(void) interrupt 4
{
    if(RI)
    {
        if(uart_rxindex == 10)
            uart_rxindex = 0;
        uart_rxbuf[uart_rxindex++] = SBUF;
        RI = 0;
    }
}
char putchar(char ch)
{
    SBUF = ch;
    while (TI == 0);    // 等待发送完成
    TI = 0;             // 发送完成标志位置0
    return ch;
}

uart.h

#ifndef __UART_H
#define __UART_H

#include "sys.h"

extern uchar uart_rxbuf[];

void Uart1_Init(void);


#endif

9、ultrasound

存放超声波测距函数。
ultrasound.c

#include "ultrasound.h"

sbit TX = P1^0;         //发射引脚
sbit RX = P1^1;         //接收引脚

uchar read_distance(void)
{
    uchar distance,num = 10;

    // TX引脚发送40KHz方波信号驱动超声波发送探头
    TX = 0;
    CL = 0xF3;              //设置定时初值
    CH = 0xFF;              //设置定时初值
    CR = 1;                 //定时器计时
    while(num--)
    {
        while(!CF);
        TX ^= 1;
        CL = 0xF3;      //设置定时初值
        CH = 0xFF;      //设置定时初值
        CF = 0;
    }

    //RX引脚接收时间计时计算距离
    CR = 0;
    CL = 0;             //设置定时初值
    CH = 0;             //设置定时初值
    CR = 1;
    while(RX && !CF);   //等待收到脉冲
    CR = 0;
    if(CF)              //发生溢出
    {
        CF = 0;
        distance = 255;
    }
    else                //计算距离
        distance = ((CH<<8)+CL)*0.017;
    return distance;
}

ultrasound.h

#ifndef __ULTRASOUND_H
#define __ULTRASOUND_H

#include "sys.h"

uchar read_distance(void);

#endif

四、源码

通过网盘分享的文件:蓝桥杯单片机真题练习
链接: https://pan.baidu.com/s/1vFd_uWY6sLZUkyaXt0wdkw?pwd=7few 提取码: 7few

五、内存不够

使用的时候把不用的外设驱动删掉,尤其是串口接收数组占了很大内存。
实在不够就定义到idata或xdata。具体操作文章:
内存不够

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值