蓝桥杯单片机组常用底层代码

蓝桥杯常见代码

一.基础类

1. 关闭基本外设

void close_perl(void)
{
    P0 = 0xff;
    P2 = P2&0x1f|0x80;
    P2 = P2&0x1f;

    P0 = 0x00;
    P2 = P2&0x1f|0xa0;
    P2 = P2&0x1f;
}

2.数码管转制与显示

unsigned char seg_tran(int num)
{
    unsigned char date;
    switch(num)
    {
        case	0	:	date = 	0xc0	;	break;
		case	1	:	date = 	0xf9	;	break;
		case	2	:	date = 	0xa4	;	break;
		case	3	:	date = 	0xb0	;	break;
		case	4	:	date = 	0x99	;	break;
		case	5	:	date = 	0x92	;	break;
		case	6	:	date = 	0x82	;	break;
		case	7	:	date = 	0xf8	;	break;
		case	8	:	date = 	0x80	;	break;
		case	9	:	date = 	0x90	;	break;
		case	10	:	date = 	0xbf	;	break;//-
		case	11	:	date = 	0xc6	;	break;//c
		case	12	:	date = 	0x8c	;	break;//p
		case	13	:	date = 	0x86	;	break;//e
		case	14	:	date = 	0xc7	;	break;//L
		case 	15	:	date = 	0xc8	;	break;//a
    }
    return date;
}

void seg_disp(int adr,int num)
{
    unsigned char seg_adr[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

    P2 = P2&0x1f|0xe0;
    P2 = P2&0x1f;
    P0 = seg_adr[adr];

    P2 = P2&0x1f|0xc0;
    P2 = P2&0x1f;
    P0 = seg_tran(num);

    P2 = P2&0x1f|0xe0;
    P2 = P2&0x1f;
}

//若需要显示小数点
void seg_disp_f(int adr,int num)
{
    unsigned char seg_adr[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

    P2 = P2&0x1f|0xe0;
    P2 = P2&0x1f;
    P0 = seg_adr[adr];

    P2 = P2&0x1f|0xc0;
    P2 = P2&0x1f;
    P0 = seg_tran(num)&0x7f;

    P2 = P2&0x1f|0xe0;
    P2 = P2&0x1f;
}

3.按键

(1) 独立按键扫描
int key_scan(void)
{
	int key_mark;
    P3 = 0x0f;

    if(P30 == 0)	key_mark = 7;
	else if(P31 == 0)	key_mark = 6;
	else if(P32 == 0)	key_mark = 5;
	else if(P33 == 0)	key_mark = 4;

    return key_mark;
}
(2) 矩阵按键扫描
int key_scan(void)
{
	int key,key_mark;
    P3 = 0x0f;

    P44 = 0;P42 = 1;P35 = 1;P34 = 1;key = P3;
    P44 = 1;P42 = 0;    key = (key<<4)|(P3&0x0f);
    P42 = 1;P35 = 0;    key = (key<<4)|(P3&0x0f);
    P35 = 1;P34 = 0;    key = (key<<4)|(P3&0x0f);
    
    switch(~key)
    {
        case 0x8000: key_mark = 4;break; 
		case 0x4000: key_mark = 5;break; 
		case 0x2000: key_mark = 6;break; 
		case 0x1000: key_mark = 7;break; 
		case 0x0800: key_mark = 8;break; 
		case 0x0400: key_mark = 9;break; 
		case 0x0200: key_mark = 10;break; 
		case 0x0100: key_mark = 11;break; 
		case 0x0080: key_mark = 12;break; 
		case 0x0040: key_mark = 13;break; 
		case 0x0020: key_mark = 14;break; 
		case 0x0010: key_mark = 15;break; 
		case 0x0008: key_mark = 16;break; 
		case 0x0004: key_mark = 17;break; 
		case 0x0002: key_mark = 18;break; 
		case 0x0001: key_mark = 19;break; 
		default    : key_mark = 0 ;break;//这句很重要,必须有!
    }

    return key_mark;
}
(3) 按键主函数

分为是否需要长按短按判断

以下为不需要:
unsigned char key_old;
void key_pro(void)
{
    unsigned char key_vol,key_down;

    key_vol = key_scan();
    key_down = key_vol&(key_vol^key_old);
    key_old = key_vol;

    switch(key_down)
    {
        case 4:
            //a
        break;

        case 5:
            //b
        break;
        //....
    }
}
以下为需要:
unsigned char key_old;//存放上一次按键值

unsigned char long_press_flag;//是否允许长按
unsigned char long_press_count;//记录长按时长

void Timer0Init(void)		//1毫秒中断@12.0MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x20;		//设置定时初值
	TH0 = 0xD1;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
}

void key_pro(void)
{
    unsigned char key_vol,key_down;

    key_vol = key_scan();
    key_down = key_vol&(key_vol^key_old);
    key_old = key_vol;

    switch(key_down)
    {
        case 4:
            //a
        break;

        case 5:
            long_press_flag = 1;
        break;
        //....
    }
}

void timer0(void)   interrupt   1
{
    if((long_press_flag == 1)&&(key_old != 0))
    {
        long_press_count ++;
    }
    else 
    {
        //假设  1s  以上为长按(包括 1s  )
        if(long_press_count >= 1000)//长按
        {
            //b
        }
        else if((long_press_flag > 0)&&(long_press_flag < 1000>))//短按
        {
            //c
        }
        long_press_count = 0;
        long_press_flag = 0;
    }
}

二.中等类

1.温度(DS18B20)

(1) 整数
unsigned char temp_read(void)
{
    unsigned char low,high,temp;
    
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0x44);
    Delay_OneWire(200);//延时700ms左右

    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);

    low = Read_DS18B20();
    high = Read_DS18B20();
    temp = (high << 4)|(low >> 4);

    return temp;
}
(2) 浮点数
float temp_read(void)
{
    unsigned char low,high,temp;
    float temp_f;

    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0x44);
    Delay_OneWire(200);//延时700ms左右

    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);

    low = Read_DS18B20();
    high = Read_DS18B20();
    temp = (high << 4)|(low >> 4);

    temp_f = temp + (low&0x0f)*0.0625;
    return temp_f;
}

2.时间(DS1302)

//该模块底层驱动官方所给文件已经给好。
unsigned char write_adress[8] = {0x80,0x82,0x84};//芯片手册有
unsigned char read_adress[8] = {0x81,0x83,0x85};//芯片手册有
unsigned char time_first[8] = {0x50,0x59,0x16};//写入初始时间   16点59分50秒

void write_into_ds1302(void)
{
    int i;
    Write_Ds1302(0x8e,0);//关闭写保护
    for(i=3;i>0;i--)
    {
        Write_Ds1302(write_adress[i],time_first[i]);
    }
    Write_Ds1302(0x8e,1);//开启写保护
}

3.ADC与DAC(PCF8591)

unsigned char pcfadc(void)//adc读取电压值
{
    unsigned char adc;
    IIC_Start();

    IIC_SendByte(0x90);
    IIC_WaitAck();
    IIC_SendByte(0x43);//根据题目要求调整地址
    IIC_WaitAck();

    IIC_Start();

    IIC_SendByte(0x91);
    IIC_WaitAck();
    adc = IIC_RecByte();
    IIC_WaitAck();

    IIC_Stop();
    return adc;
}

void pcfdac(unsigned char dac)//dac写入电压值
{
    IIC_Start();

    IIC_SendByte(0x90);
    IIC_WaitAck();
    IIC_SendByte(0x43);
    IIC_WaitAck();
    IIC_SendByte(dac);
    IIC_WaitAck();

    IIC_Stop();
}

4.EEPROM读与写(AT24C02)

void eewrite(unsigned char adress,unsigned char date)
{
    EA = 0;

    IIC_Start();

    IIC_SendByte(0xa0);
    IIC_SendAck();
    IIC_SendByte(adress);
    IIC_SendAck();
    IIC_SendByte(date);
    IIC_SendAck();

    IIC_Stop();

    EA = 1;
}

unsigned char eeread(unsigned char adress)
{
    unsigned char date;

    EA = 0;

    IIC_Start();

    IIC_SendByte(0xa0);
    IIC_SendAck();
    IIC_SendByte(adress);
    IIC_SendAck();

    IIC_Start();

    IIC_SendByte(0xa1);
    IIC_SendAck();
    date = IIC_RecByte();
    IIC_SendAck();

    IIC_Stop();
   
    EA = 1;

    return date;
}

5.NE555频率计

unsigned int count;
unsigned int frequence;
unsigned int timer1_up;

//同时利用计数器和定时器
void timer_init(void)
{
    TMOD = 0x16;
    
    TH0 = 0xff;//**
    TL0 = 0xff;//**
    TH1 = (65535 - 50000+1)/256;
    TL1 = (65535 - 50000+1)%256;

    TF0 = 0;
    TR0 = 1;
    ET0 = 1;
    
    TF1 = 0;
    TR1 = 1;
    ET1 = 1;

    EA = 1;
}

void timer0(void)   interrupt 1
{
    count   ++;
}

void timer1(void)   interrupt 3
{
    timer1_up++;
    if(timer1_up == 20)
    {
        frequence = count;
        count = 0;
        timer1_up = 0;
    }
}

三.国赛类

1.超声波

sbit TX=P1^0;//发送端
sbit RX=P1^1;//接收端
unsigned int distance;//定义距离

void Delay12us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	_nop_();
	_nop_();
	i = 30;
	while (--i);
}

void  send_wave(void)//发送8个40KHz超声波信号
{
    int i;
    for(i = 0;i < 8;i ++)
    {
        TX = 1;
        Delay12us();
        TX = 0;
        Delay12us();
    }
}

void distance_get(void)
{
    unsigned int time = 0;

    AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x00;		//设置定时初值
	TH0 = 0x00;		//设置定时初值
    
    send_wave();

    TR0 = 1;//开始计时
    while((RX == 1)&&(TF0 == 0));//等待接受
    TR0 = 0;//关闭定时器

    if(TF0 == 0)//没有溢出(定时器溢出标志位不为1)
    {
        time = TH0;
        time = (time << 8)|TL0;//***左移8位
        distance = time*0.017;     
    }
    else //超出距离
    {
        TF0 = 0;//定时器溢出标志位置0
        distance = 999;
    }
}

2.串口通讯

unsigned char command;//储存从电脑读出的数据
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
	TL1 = 0xE0;		//设定定时初值
	TH1 = 0xFE;		//设定定时初值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
    
    EA = 1;//开启中断
    ES = 1;//开启串口通讯
}

void  SendByte(unsigned char date)
{
    SBUF = date;//将数据写入缓冲寄存器
    while(TI == 0);//等待发送完成
    TI = 0;//关闭标志位,保证下次传输
}

void uart(void) interrupt 4
{
    if(RI == 1)//单片机是否接收完数据
    {
        command = SBUF;
        RI = 0;//标志位置0
        SendByte(command+1);//给电脑发一个数据表示收到了 ***
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值