蓝桥杯省赛模板(自用)

1.主体代码(初始化 数码管 键盘 )

//@12.0Mhz
#include <STC15F2K60S2.H>
#define keyscan() keyscan_KBD()//函数替换
typedef unsigned char uchar;
typedef unsigned int uint;
//独立按键
sbit k7=P3^0;
sbit k6=P3^1;
sbit k5=P3^2;
sbit k4=P3^3;
//矩阵键盘
sbit C4=P3^4;
sbit C3=P3^5;
sbit C2=P4^2;
sbit C1=P4^4;

//数码管变量
code uchar smg_dm[]={
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0xff, //10- 关闭
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e //F
};
uchar smg_num[8]={10,10,10,10,10,10,10,10};
uchar com=0;
//全局变量
bit key_flag=0;//键盘扫描标志位
uchar key_con=0;//键盘扫描计数
uchar key_s=0;//键值
uchar key_temp=0;//键值暂存
uchar key_press=0;//按下计数(用于消抖)

uchar led_s=0;//保存led的值(高电平有效)
uchar pos=0;
uchar led_con=0;
//函数
void hc138(uchar n){//选通573
	if(n==0) P2=P2&0x1f|0x00;
	if(n==4) P2=P2&0x1f|0x80;
	if(n==5) P2=P2&0x1f|0xa0;
	if(n==6) P2=P2&0x1f|0xc0;
	if(n==7) P2=P2&0x1f|0xe0;
}
void init(){//初始化关闭外设
	hc138(4);
	P0=0xff;
	hc138(5);
	P0=0x00;
	hc138(0);
}
void dsp(){//数码管显示
	hc138(6);
	P0=0x00;
	hc138(0);
	hc138(7);
	P0=smg_dm[smg_num[com]];
	hc138(0);
	hc138(6);
	P0=0x01<<com;
	hc138(0);//这一步是必要的,可以更好的排除其他操作(如LED)对显示的干扰
	com=(com+1)%8;//使com在0-7循环
}
uchar keyscan_BTN(){//独立按键扫描程序
	k7=k6=k5=k4=1;
	if(k7==0) return 7;
	if(k6==0) return 6;
	if(k5==0) return 5;
	if(k4==0) return 4;
	return 0;
}
uchar keyscan_KBD(){//矩阵键盘扫描程序
	uchar i;
	C1=C2=C3=C4=1;
	for(i=0;i<=3;i++){
//		P3=(P3&0xf0)|((~(0X01<<i))&0x0f);
		P3=~(0x01<<i);
		if(C1==0){
			return 3-i+4;
		}
		if(C2==0){
			return 3-i+8;
		}
		if(C3==0){
			return 3-i+12;
		}
		if(C4==0){
			return 3-i+16;
		}
	}
	return 0;
}
void keyout(){//键值输出程序
	if(key_flag){
		key_flag=0;
		key_temp=keyscan();
		if(key_temp==key_s) return;
		if(key_temp!=0){
			key_press++;
		}else{
			key_s=0;
			key_press=0;
			return;
		}
		if(key_press==3){
			key_press=0;
			key_s=key_temp;
			return;
		}
	}
}
void led(){//LED测试
	P0=0xff;
	hc138(4);
	P0=~led_s;
	hc138(0);
	P0=0xff;
}
//================定时器================//
void Timer0Init(void)		//1毫秒@12.000MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x20;		//设置定时初始值
	TH0 = 0xD1;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}
void Timer0ser() interrupt 1{//定时器0服务程序,用于数码管显示和其他各种程序定时
	//(定时器1可用于串口,555频率检测等)注意:定时器2的使能位在IE2,不能位寻址
	dsp();
	led();
	if(key_con++==10){//键盘扫描计时
		key_con=0;
		key_flag=1;
	}
	if(led_con++==200){//流水灯
		led_con=0;
		led_s=0x01<<pos;
		pos=(pos+1)%8;
	}
}
//=====================================//
void main(){
	init();
	Timer0Init();
	EA=1;
	ET0=1;
	while(1){
		keyout();
		smg_num[6]=key_s/10;
		smg_num[7]=key_s%10;
	}
}

2. DS18B20温度传感器

头文件书写 onewire.h(注意最后空一行)

头文件引入和管脚定义写在.c文件里面

#ifndef _ONEWIRE_H
#define _ONEWIRE_H


void Delay_OneWire(unsigned int t);
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);
bit init_ds18b20(void);

#endif

驱动文件修改

画红线处添加一行

温度读取和数据处理

void start(){
	init_ds18b20();
	Write_DS18B20(0xcc);//跳过rom
	Write_DS18B20(0x44);//开始转换
}

long read_temp(){
	long temp;
	unsigned char low,high;
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);//读取温度
	low=Read_DS18B20();//先读低位
	high=Read_DS18B20();//再读高位
	temp=(high<<8)|low;
	temp=temp*625;//得到一个六位数 后四位为小数部分
	
	return temp;
}

在主函数中的写法为:

//先在初始化的时候开始转换,然后每700ms读取一次温度,读取结束后再开始转换
//(为避免数据抽风,温度转换间隔需要至少700ms)
void main(){
	init();
	Timer0Init();
	EA=1;
	ET0=1;
	start();
	while(1){
		keyout();
		smg_num[6]=key_s/10;
		smg_num[7]=key_s%10;
		testapp();
	}
}

void testapp(){//测试数据
	if(test_flag){
		test_flag=0;
		test=read_temp();
		start();
		smg_num[0]=test/100000%10;
		smg_num[1]=test/10000%10+11;
		smg_num[2]=test/1000%10;
		smg_num[3]=test/100%10;
		smg_num[4]=test/100%10;
	}
}

3.时钟DS1302

头文件书写 ds1302.h

#ifndef _DS1302_H
#define _DS1302_H


void Write_Ds1302(unsigned  char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte ( unsigned char address );

#endif

原理

ROM表
读写操作的地址如上表所示:

  • 寄存器的 BIT7 定义为时间暂停位,当 BIT1 为 1 时,时钟振荡器停止工作,DS1302 进入低功耗模式,电源消耗小于 100 微安,当 BIT1 为 0 时,时钟振荡器启动,DS1302 正常工作。

  • 小时寄存器的 BIT7 定义为 12 或 24 小时工作模式选择位,当 BIT7 为高时,为 12 小时工作模式,此时 BIT5 为 AM/PM 位电平标示 AM,电平标示PM,在 24 小时模式下,BIT5 为第二个 10 小时位标示(20~23 时)。

  • 写保护寄存器的 BIT7:WP 是写保护位,工作时,出 WP 外的其他位都置为0,对时钟/日历寄存器或 RAM 进行写操作之前,WP 必须为 0,当 WP 为高电平的时候,不能对任何时钟/日历寄存器或 RAM 进行写操作。

  • DS18B20的数据为16进制的BCD码,获取高位数字应该/16,获取低位数字%16.

时间读取

变量

uchar DS1302r_add[] = {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};	//DS1302读数据的地址
uchar DS1302w_add[] = {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};	//DS1302写数据的地址
uchar timer[] = {0x50,0x59,0x23,0x05,0x09,0x07,0x23};				//2023年,4月1日,23时59分50秒

初始化函数

void DS1302_Init(void)//ds1302初始化
{
	uint n;
	Write_Ds1302_Byte(0x8E,0x00);//允许写
	for(n=0;n<7;n++)
	{
		Write_Ds1302_Byte(DS1302w_add[n],timer[n]);
	}
	Write_Ds1302_Byte(0x8E,0x80);//禁止写
}

读时间

void Read_DS1302_Time(void)//读日期
{
	uint n;
	for(n=0;n<7;n++)
	{
		timer[n] = Read_Ds1302_Byte ( DS1302r_add[n]);
	}
}

数据显示

		smg_num[0]=timer[0]/16;//秒十位
		smg_num[1]=timer[0]%16;//秒个位
		smg_num[2]=timer[1]/16;//。。。
		smg_num[3]=timer[1]%16;
		smg_num[4]=timer[2]/16;
		smg_num[5]=timer[2]%16;

4.A/DC和EEPROM

eeprom(设备地址A0)

void eeprom_write(unsigned char add,dat){
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(add);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}

unsigned char eeprom_read(unsigned char add){
	unsigned char dat;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(add);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	dat=I2CReceiveByte();
	I2CSendAck(1);//1-非应答 0-应答
	I2CStop();
	return dat;
}

A/DC (设备地址90)

原理

在这里插入图片描述

ADC

以光敏电阻为例子,I2CSendByte(0x01); bit7为1的时候是模拟输出,bit7为0的时候是数字转换读取数据

unsigned char adc(){
	unsigned char dat;
	I2CStart();
	I2CSendByte(0x90);//设备地址写
	I2CWaitAck();
	I2CSendByte(0x01);//写入开始转换的通道 AIN1 RB1光敏电阻
	I2CWaitAck();
	
	I2CStart();//重新开始IIC
	I2CSendByte(0x91);//设备地址读
	I2CWaitAck();
	dat=I2CReceiveByte();
	I2CSendAck(1);//非应答1
	I2CStop();
	return dat;
}

数据处理
rb1数据类型为uint,乘100再除以51是为了转换为三位的整数值代表电压,0-5v,后两位为小数部分

	rb1=adc();
	rb1=rb1*100/51;
	smg_num[0]=rb1/100+11;
	smg_num[1]=rb1/10%10;
	smg_num[2]=rb1%10;

DAC

void dac(unsigned char dat){
	I2CStart();
	I2CSendByte(0x90);//设备地址
	I2CWaitAck();
	I2CSendByte(0x41);//开始DA转换,写入地址
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}

数据处理
要转换的0-5v电压乘以51即可。

5.串口通信(时钟1为频率源)

void bytesend(uchar dat){//传输单个字符
	SBUF=dat;
	while(TI==0);
	TI=0;
}
void stringsend(char *p){//传输字符串
	while(*p!='\0'){//\0为字符结束标志
		bytesend(*p);
		p++;
	}
}
void testapp(){//测试数据
	if(test_flag){
		test_flag=0;
		stringsend("abcdefg\n");
		stringsend(rec_str);
	}
}
void UartInit(void)		//9600bps@12.000MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器时钟1T模式
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0xC7;		//设置定时初始值
	TH1 = 0xFE;		//设置定时初始值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时
	ES = 1;			//开启串口中断
}
void UART() interrupt 4{
	if(RI){
		RI=0;
		dat=SBUF;
		if(dat!='\n'){
			rec_str[a]=dat;
			a++;
		}else{
			rec_str[a+1]='\n';
			rec_str[a+2]='\0';
			a=0;
		}
	}
}

6.555频率测量

需要用到定时器0的计数器模式,

void Timer0Init(void)		//1毫秒@12.000MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD |= 0x04;		//设置定时器模式 0x04为 bit3 C/T位置1 变为计数器模式
	TL0 = 0x00;		//设置定时初始值
	TH0 = 0x00;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA=1;
	ET0=1;
}

在定时器1中断中一秒钟读取一次TL0和TH0的数据 得到的就是频率

if(fre_con++==1000){//pcf8591 1s刷新一次
		TR0=0;
		fre_con=0;
		fre_temp=TH0<<8;
		fre_temp+=TL0;
		TH0=0x00;
		TL0=0x00;
		frequency=fre_temp;
		TR0=1;
	}

超声波(用CAP定时器)

定时器初始化(开始的时候就发送一个超声波)然后开始计时,负脉冲中断使能

void initpca(){//12M pca定时器
	CCON = 0;//清除控制寄存器
	CMOD = 0x01;//1mhz模式 打开溢出中断使能
	CCAPM0 = 0x11;//负脉冲 使能ccp0
	CR=0;
	sendultrasonic();//发送一个超声波
}

超声波发送程序
发送八个方波,延时13us!!
并且开始计时

void sendultrasonic(){
	EA=0;
	p10=1;Delay13us();p10=0;Delay13us();
	p10=1;Delay13us();p10=0;Delay13us();
	p10=1;Delay13us();p10=0;Delay13us();
	p10=1;Delay13us();p10=0;Delay13us();
	p10=1;Delay13us();p10=0;Delay13us();
	p10=1;Delay13us();p10=0;Delay13us();
	p10=1;Delay13us();p10=0;Delay13us();
	p10=1;Delay13us();p10=0;
	EA=1;
	CL=0;//清零计时器
	CH=0;//清零计时器
	CR=1;//开始计时
}

接收的中断程序(每100ms接收一次)
读取定时的值然后再发送超声波,若超量程则变成999

void testapp(){//测试数据
	if(test_flag){
		test_flag=0;
		if(CF){
			CF=0;
			distance=999;//超量程
		}else{
			distance=CCAP0H;
			distance=(distance<<8)|CCAP0L;
			distance+=150;//加上发送时间的150个值
			distance=(float)distance*0.017;
		}
		smg_num[0]=distance/100;
		smg_num[1]=distance/10%10;
		smg_num[2]=distance%10;
		sendultrasonic();
	}
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值