蓝桥杯单片机国赛模板——基于柳离风模板

蓝桥杯单片机国赛模板——基于柳离风模板

文章目录

  • 蓝桥杯单片机国赛模板——基于柳离风模板
    • 一、工程结构
    • 二、USER文件夹
      • main.c
    • 三、BSP文件夹
      • 1、sys
      • 2、display
      • 3、key
      • 4、timer
      • 5、iic
      • 6、ds1302
      • 7、onewire
      • 8、uart
      • 9、ultrasound
    • 四、源码
    • 五、内存不够

一、工程结构

在这里插入图片描述
与省赛模板相比增加了串口接收处理,简化超声波,优化细节。

二、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] = {21,21,21,21,21,21,21,21};   //数码管显示
uchar dot[8] = {0,0,0,0,0,0,0,0};           //小数点显示
uchar LED[8] = {0,0,0,0,0,0,0,0};           //led显示
uchar state_display = 1;                    //显示状态
uint temperature;                           //温度变量
idata uchar distance;                       //距离,内存爆了就用idata/* 函数区 */
//显示任务
void display_task(void)
{/*LED任务*///放在延迟判断前,这样闪烁间隔才正常LED[0] = 0;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] = 21;SMG[2] = 21;SMG[3] = (fre<10000) ? 21:fre/10000;SMG[4] = (fre<1000) ? 21:fre/1000%10;SMG[5] = (fre<100) ? 21:fre/100%10;SMG[6] = (fre<10) ? 21:fre/10%10;SMG[7] = fre%10;break;case 1:    /*距离显示*/SMG[0] = 21;SMG[1] = 21;SMG[2] = 21;SMG[3] = 21;SMG[4] = 21;SMG[5] = (distance<100) ? 21:distance/100;SMG[6] = (distance<10) ? 21:distance/10%10;SMG[7] = distance%10;break;}
}//采集任务
void collect_task(void)
{if(collect_dly<300)return;collect_dly = 0;temperature = ds18b20_read(0);distance = read_distance();
//    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:  state_display = (state_display+1)%2;break;case 5:  state_beep = ~state_beep;break;case 8:  state_relay = ~state_relay;break;case 9:  break;}
}void uart_task(void)
{if(uart_rxindex == 0)return;if(uart_dly>=10){uart_dly = 0;flag_uart = 0;//解析数据,这些内置字符串函数会使内存暴增,注释掉看看会发现内存变化很大,不用时一定注释掉
//        sscanf(uart_rxbuf,"(%d,%d)",&temperature,&distance);
//        printf("%s",uart_rxbuf);memset(uart_rxbuf,0,10);uart_rxindex = 0;}}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);//第二次读一定接收到变量里,否则默认是0AT24C02_write(1,123);       //EEPROM初始化-写入值,连续写时要加延时EA = 1;                     //打开总中断while(1){key_task();collect_task();display_task();uart_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"
#include "string.h"
#include "math.h"#define uchar unsigned char
#define uint unsigned int
//任选一种命名方式
//typedef unsigned char uchar;
//typedef unsigned int uint;void hc573(uchar channel);
void sys_init(void);
void delay_ms(uint xms);
void delay_us(uint xus);#endif

2、display

存放显示驱动函数,包括LED,数码管,继电器,蜂鸣器等外设的控制。数码管段表在资源包里有,如果需要特殊字符可以在STC-ISP范例程序里找实验箱hc595驱动8个共阴极数码管,但是比赛用的是共阳极数码管,所以要用计算器取反
在这里插入图片描述
在这里插入图片描述

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
0xc7, //L17
0x8c, //P18
0xc1, //U19
0xbf, //-20
0xff  //灭21
};/*** @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;elseP0 = Seg_Table[SMG[pos]];hc573(7);
}/*** @brief 继电器控制* * @param state_relay 0关1开*/
void relay(uchar state_relay)
{if(state_relay)uln2003 |= 0x10;elseuln2003 &= ~0x10;P0 = uln2003;hc573(5);
}/*** @brief 蜂鸣器控制* * @param state_beep 0关1开*/
void beep(uchar state_beep)
{if(state_beep)uln2003 |= 0x40;elseuln2003 &= ~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"
#include "uart.h"unsigned long systick_ms = 0;       //滴答定时器
uchar key_dly = 0;                  //按键任务调度
uint display_dly = 0;               //显示任务调度
uint collect_dly = 0;               //采集任务调度
uchar uart_dly = 0;                 //串口任务调度
uchar pos = 0;                      //数码管led扫描位置
uint count_1s = 0;                  //1s计时测频率
uint fre;                           //频率
bit state_relay = 0;                //继电器状态
bit state_beep = 0;                 //蜂鸣器状态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(flag_uart==1)uart_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 uart_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  10sbit 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);      //应答elseI2CSendAck(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的读写,只保留了秒分时,使用时注意BCD码转换/16,%16,这里存放的是BCD码
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),注意如果要保留小数,温度变量定义时一定要用uint,不要用uchar,不保留小数uchar即可
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);            //跳过ROMWrite_DS18B20(0x44);            //开始温度转换init_ds18b20();                 //初始化Write_DS18B20(0xcc);            //跳过ROMWrite_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

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

#include "uart.h"
#include "timer.h"uchar uart_rxbuf[10];               //串口接收数组
uchar uart_rxindex;                 //串口接收数组索引
bit flag_uart;                      //串口接收标志//串口初始化
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){flag_uart = 1;uart_dly = 0;uart_rxbuf[uart_rxindex++] = SBUF;if(uart_rxindex == 10)uart_rxindex = 0;RI = 0;}
}//重定向printf
char putchar(char ch)
{SBUF = ch;while (TI == 0);    // 等待发送完成TI = 0;             // 发送完成标志位置0return ch;
}

uart.h

#ifndef __UART_H
#define __UART_H#include "sys.h"extern uchar uart_rxbuf[];                 //串口接收数组
extern uchar uart_rxindex;                 //串口接收数组索引
extern bit flag_uart;                      //串口接收标志
void Uart1_Init(void);#endif

9、ultrasound

存放超声波测距函数,40khz起始方波可由PCA生成,也可由软件延时生成,软件延时效果不好的话调一下i值,目前调到38比较合适
ultrasound.c

#include "ultrasound.h"sbit TX = P1^0;         //发射引脚
sbit RX = P1^1;         //接收引脚//方波延时
void delay12us(void)    //@12.000MHz
{unsigned char data i;_nop_();_nop_();i = 38;             //如果效果不好就调这个值,试试38while (--i);
}//读取距离,延时生成方波
uchar read_distance(void)
{uchar distance;uchar i;//初始化,计时器清零CMOD = 0x00;CH= CL = 0;//产生40kHz起始信号for(i = 0;i < 8;i++){TX = 1;delay12us();TX = 0;delay12us();}CR = 1;//开始计时while((RX == 1) && (CF == 0));   //等待收到脉冲或者定时器溢出CR = 0;//停止计时if(CF == 1)              //发生溢出,说明没有反射回来{CF = 0;//清除溢出distance = 255;}else                    //没有溢出,反射回来,计算距离distance = ((CH << 8) | CL)*0.017;return distance;
}//读取距离,PCA生成方波
//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

五、内存不够

使用的时候把不用的外设驱动删掉,尤其是串口接收数组占了很大内存,滴答定时器systick变量不用的话注释掉,二值标志位尽量用bit型,内置的字符串处理函数如printf,sscanf不需要的话不要随便用,会使内存暴增,不够了就用idata。
实在不够就定义到pdata或xdata。具体操作文章:
内存不够

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/79799.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C与指针——常见库函数

字符串 #include<stdlibs.h> int abs(int); long labs(long); int rand(void);//0-RAND_MAX //字符串转值 int atoi(const char*); long atol(const char*); float atof(const char*);数学\排序 #include<math.h> \\常见三角&#xff0c;sqrt(); exp(); double p…

数学复习笔记 2

前言 朋友和我讨论了一个二重积分题&#xff0c;非常有意思。内容非常细致。整理如下&#xff1a; 二重积分 题目来源是 1000 上面的 16 题&#xff0c;积分区域是一个偏心圆&#xff0c;偏心圆的圆心在 y 轴上面&#xff0c;偏心圆是关于 y 轴对称的&#xff0c;可以看关于…

Javaweb项目--Mybatis,导入com.mysql.cj.jdbc.Driver时报错,Cannot resolve class ‘Driver‘

目录 问题解决方法结果 问题 在项目java文件下&#xff0c;包文件下的application.properties文件中&#xff0c;项目目录如下&#xff1a; 报错信息如下&#xff1a; 解决方法 在pom.xml文件中增加此依赖 结果 报错信息消失

分布式-redisson

分布式锁redisson 加锁流程缓存相关问题 加锁流程 redisson底层通过lua脚本实现加锁的原子性lock动作包含&#xff1a;加锁、设置超时时间、锁续命未获取到锁的线程通过获取信号量许可等待&#xff0c;所释放后释放信号量通知等待线程 缓存相关问题 缓存失效&#xff08;击穿…

Java基础学完,继续深耕(0505)Linux 常用命令

昨天休息了一天&#xff0c;没有写csdn 昨天和今天把Linux大概学了一下。总结一下常用命令&#xff0c;总结的不全。 Linux目录结构 / 是所有目录的顶点 目录结构像一颗倒挂的树 注意&#xff1a;/itheima 是绝对路径&#xff0c;是指根目录 / 下的itheima目录 itheima…

【AI论文】Sadeed:通过小型语言模型推进阿拉伯语变音

摘要&#xff1a;由于语言的形态丰富&#xff0c;阿拉伯语文本的变音符号仍然是自然语言处理中一个持续的挑战。 在本文中&#xff0c;我们介绍了一种基于微调解码器语言模型的新方法Sadeed&#xff0c;该方法改编自Kuwain 1.5B Hennara等人[2025]的模型&#xff0c;该模型最初…

学习海康VisionMaster之亮度测量

一&#xff1a;进一步学习了 今天学习下VisionMaster中的亮度测量&#xff1a;这个和前面学习的都不一样了&#xff0c;这个是测量ROI区域内的平均亮度等 1&#xff1a;什么是亮度测量&#xff1f; 我们工业上用的相机里面有一个感光芯片&#xff08;CCD/CMOS&#xff09;&…

学习路线(python)

Python从初级到专家的学习路线# 初级阶段 (1-3个月)基础语法数据结构文件操作推荐资源 中级阶段 (3-6个月)面向对象编程常用模块错误处理进阶特性推荐资源 高级阶段 (6-12个月)并发编程性能优化元编程设计模式推荐资源 专业方向 (选择1-2个方向深入)Web开发数据分析/科学计算机…

svn文件提交失败

这里写自定义目录标题 1报错项目2.解决办法1.安装sqlite3.exe 数据库2.sqlite3.exe放到svn 项目的主目录下&#xff0c;和.svn目录同级下, 可以直接在数据库目录下执行cmd命令。3.在当前目录下 cmd 运行命令 4.最后再项目的文件夹下&#xff0c;看是否可以 clean up了。--成功&…

调试——GDB、日志

调试——GDB、日志 1. gdb常用指令2. 如何生成core文件并调试&#xff1f;3. 如何调试正在运行的程序4. 调试多进程程序5. 调试多线程程序6. log日志 gcc编译器可以帮我们发现语法错误&#xff0c;但是对业务逻辑错误却无能为力。当我们想找出逻辑错误时&#xff0c;就需要调试…

redis----通用命令

文章目录 前言一、运行redis二、help [command]三、通用命令 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 学习一些通用命令 以下操作在windows中演示 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、运行redis 我们先c…

CatBoost算法原理及Python实现

一、概述 CatBoost 是在传统GBDT基础上改进和优化的一种算法&#xff0c;由俄罗斯 Yandex 公司开发&#xff0c;于2017 年开源&#xff0c;在处理类别型特征和防止过拟合方面有独特优势。 在实际数据中&#xff0c;存在大量的类别型特征&#xff0c;如性别、颜色、类别等&#…

五一假期作业

sub_process.c #include <stdio.h> // 标准输入输出库 #include <pthread.h> // POSIX线程库 #include <sys/ipc.h> // IPC基础定义&#xff08;如消息队列/共享内存&#xff09; #include <sys/msg.h> // 消息队列操作相关…

Liunx安装Apache Tomcat

目录 一、了解tomcat 二、下载 三、启动tomcat 四、网页访问tomcat 五、Tomcat修改默认8080端口 六、Tomcat创建项目步骤-实现项目对外访问 一、了解tomcat Apache Tomcat 是一个开源的 Java Servlet 容器 和 Web 服务器&#xff0c;主要用于运行基于 Java 的 Web 应用…

破局者手册 Ⅰ:测试开发核心基础,解锁未来测试密钥!

目录 一、引入背景 二、软件测试基础概念 2.1 软件测试的定义 2.2 软件测试的重要性 2.3 软件测试的原则 三、测试类型 3.1 功能测试 3.2 接口测试 3.2.1 接口测试的概念 3.2.2 接口测试的重要性 3.2.3 接口测试的要点 3.2.4 接口测试代码示例&#xff08;Python r…

C++ 适配器模式详解

适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许不兼容的接口之间能够协同工作。 概念解析 适配器模式的核心思想是&#xff1a; 接口转换&#xff1a;将一个类的接口转换成客户希望的另一个接口 兼容性&#xff1a;使原本由于接…

【NLP】 28. 语言模型的评估方式:MRR, PERPLEXITY, BLEU, WER从困惑度到实际效果

语言模型的评估方式&#xff1a;从困惑度到实际效果 评估语言模型&#xff08;LLM&#xff09;是否有效&#xff0c;并不仅仅是看它生成句子是否“听起来通顺”&#xff0c;我们需要定量的指标对模型性能做出系统性评价。评估方法主要分为两大类&#xff1a; 内在评价&#x…

Java 企业级开发设计模式全解析

Java 企业级开发设计模式全解析 在 Java 企业级开发的复杂领域中&#xff0c;设计模式如同精湛的工匠工具&#xff0c;能够帮助开发者构建高效、可维护、灵活且健壮的软件系统。它们是无数开发者在长期实践中总结出的解决常见问题的最佳方案&#xff0c;掌握这些模式对于提升开…

小刚说C语言刷题—1038编程求解数学中的分段函数

1.题目描述 编程求解数学中的分段函数。 …………x1 (当 x>0 )。 yf(x)…0 (当 x0 )。 ………x−1 (当 x<0 )。 上面描述的意思是&#xff1a; 当x>0 时 yx1 ; 当 x0 时 y0 ; 当 x<0 时 yx−1 。 输入 输入一行&#xff0c;只有一个整数x(−30000≤x≤30…

滚珠螺杆的精度如何保持?

滚珠螺杆通常用于需要精确定位的地方&#xff0c;高机械效率、低传递扭矩和几乎为零的轴向游隙&#xff0c;使滚珠螺杆成为工具定位和飞机副翼驱动等应用中的重要设备。但是&#xff0c;连续工作产生的阻力和热量会导致较大的摩擦力和定位误差。那么&#xff0c;滚珠螺杆的精度…