栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

蓝桥杯单片机模块代码综合(考前快速复习)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

蓝桥杯单片机模块代码综合(考前快速复习)

今天做的是蓝桥杯所有模块的综合,只展示模块的核心代码,所以只能作为复习资料,而不是学习资料。这次给原理图全在官方给的资料里,考试记不起来可以在文件夹里找到!

(一)LED

  核心代码示例:

void lighten(u8 led)
{
  P0=~led;
  P2=P2&0x1F|0x8F;
  P2=P2&0x1F;
}

原理图: 

 回忆一下,译码器选择Y4使得其为低电平,J13中WR与地连接,所以或非门后Y4C为1,锁存器才能打开,P0的信息才能给右侧。二极管左侧为0才能亮,所以书写代码时我们常用~取反,使得P0取1为亮,取0为暗,符合人们的思维习惯。

(二)外中断

  核心代码示例: 

void open()
{
  EA=1;
  EX1=1;
  EX0=1;
  IT1=1;
  IT0=1;
}




void stop1() interrupt 0
{
  P0=~1;
  P2=P2&0x1F|0x80;
  P2=P2&0x1F;
}

void stop2() interrupt 2
{
  P0=~0;
  P2=P2&0x1F|0x80;
  P2=P2&0x1F;
}

原理图: 

 

打开中断→使用中断就可以,注意中断与中断,中断与主函数之间不能同时使用相同的引脚和期间,后果不可估计,如LED与数码管。

(三)定时器

  核心代码示例:

void Timer0Init(void)		//50毫秒@11.0592MHz
{
  AUXR &= 0x7F;		//定时器时钟12T模式
  TMOD &= 0xF0;		//设置定时器模式
  TL0 = 0x00;		//设置定时初值
  TH0 = 0x4C;		//设置定时初值
  TF0 = 0;		//清除TF0标志
  TR0 = 1;		//定时器0开始计时
}

STC-ISP直接提供代码。中断号码在上一个模块的原理图中。

(四)数码管

  核心代码示例:

void translate(u8 org[],u8 tran[])
{
  u8 k,j,mid;
  for(j=0,k=0;j<8;j++,k++)
  {
	switch(org[k])
	{
      case '0': mid = 0xc0; break;
	  case '1': mid = 0xf9; break;  
	  case '2': mid = 0xa4; break;  
	  case '3': mid = 0xb0; break;  
   	  case '4': mid = 0x99; break;  
	  case '5': mid = 0x92; break;  
	  case '6': mid = 0x82; break;  
	  case '7': mid = 0xf8; break;  
	  case '8': mid = 0x80; break;  
	  case '9': mid = 0x90; break;
      case '-':	mid = 0xbf; break;		
  	  default: mid = 0xff;
	}
	if(org[k+1]=='.')
	{
	  mid=mid&0x7f;
  	  k++;
	}
	  tran[j]=mid;
  }
}

void display(u8 tran[],u8 wei)
{
  P0=0xFF;
  P2=P2&0x1F|0xE0; 
  P2&=0x1F;
  P0=1< 

 选择对应锁存器(一)就说过了吧,不重复了。我们输入的内容在org数组中,translate函数将其翻译为共阳数码管的对应内容,再通过display函数显示,定时器快速切换,使得肉眼认为其一直亮。注:如果位选段选部分互换,可能消影不理想。

(五)矩阵键盘

    核心代码展示:

u8 search()
{
  u16 key;
  u8 key_return;
  P44=0;P42=1;P35=1;P34=1;
  key=key|(P3&0x0F);
  P44=1;P42=0;P35=1;P34=1;
  key=(key<<4)|(P3&0x0F);
  P44=1;P42=1;P35=0;P34=1;
  key=(key<<4)|(P3&0x0F);
  P44=1;P42=1;P35=1;P34=0;
  key=(key<<4)|(P3&0x0F);
  switch(~key)
  {
    case 0x8000: key_return = 4; break; // S4  
	case 0x4000: key_return = 5; break; // S5  
	case 0x2000: key_return = 6; break; // S6  
	case 0x1000: key_return = 7; break; // S7  
	case 0x0800: key_return = 8; break; // S8  
	case 0x0400: key_return = 9; break; // S9  
	case 0x0200: key_return = 10; break; // S10  
	case 0x0100: key_return = 11; break; // S11  
	case 0x0080: key_return = 12; break; // S12  
	case 0x0040: key_return = 13; break; // S13  
	case 0x0020: key_return = 14; break; // S14  
	case 0x0010: key_return = 15; break; // S15  
	case 0x0008: key_return = 16; break; // S16  
	case 0x0004: key_return = 17; break; // S17  
	case 0x0002: key_return = 18; break; // S18  
	case 0x0001: key_return = 19; break; // S19  
	default: key_return = 0; 
  }
  return key_return;
}

void key_translate()
{
  new=search();
  if(new!=old&&new!=0)
  {
    if(new>=14)
	org[7]=new-14+'A';
	else org[7]=new-4+'0';
  }
  old=new;
}

 外中断时,我们的J5的23相连,此时是12。其确定按键的形式为P34,P35,P42,P44,分别单独置0,确定列。再通过P30,P31,P32,P33确定行,从而锁定按键。记住记录按件情况的key是十六位的。

  后一个函数是根据扫描的结果执行想要的结果,通过OLD,NEW参数让一次按下只识别一次,当然如需按下切换界面,松手消失之类,需要将功能写在  if(new!=old&&new!=0)外,这句话应该看不懂,除非你做过相应省赛。

(六)时钟芯片

  核心代码示例:

void read()
{
  u8 mid;
  mid=Read_Ds1302_Byte(0x85);
  time_now[0]=(mid>>4)*10+(mid&0x0f);
  mid=Read_Ds1302_Byte(0x83);
  time_now[1]=(mid>>4)*10+(mid&0x0f);
  mid=Read_Ds1302_Byte(0x81);
  time_now[2]=(mid>>4)*10+(mid&0x0f);
}

void stop0() interrupt 0
{
  u8 mid;
  Write_Ds1302_Byte(0x8e,0);
  mid=((time_set[0]/10)<<4)+time_set[0]%10;
  Write_Ds1302_Byte(0x84,mid);
  mid=((time_set[1]/10)<<4)+time_set[1]%10;
  Write_Ds1302_Byte(0x82,mid);
  mid=((time_set[2]/10)<<4)+time_set[2]%10;
  Write_Ds1302_Byte(0x80,mid);
  Write_Ds1302_Byte(0x8e,0x80);
}

最核心的图就是这个,底层代码解释就看我以前的文章吧。其存储方式是将十位和各位分开来,所以需要转化。读取和存储看最后一位(传输时时第一位,单线嘛) ,地址图最左侧两列。写时需要打开写保护,写完后记得关闭。

(七)温度模块

  核心代码示例:

void rd_temperature(unsigned char *zhen1,unsigned char *zhen2)
{
  init_ds18b20();
  Write_DS18B20(0xcc);
  Write_DS18B20(0x44);
  Delay_oneWire(10);
  init_ds18b20();
  Write_DS18B20(0xcc);
  Write_DS18B20(0xbe);
  *zhen1=Read_DS18B20();
  *zhen2=Read_DS18B20();
}

底层代码修改见前面的文章。

我们使用的只有0xCC,0xBE,0x44。初始化→跳过ROM→转化/读温度。

读温度遵循以下规则:

先读LS BYTE,后MS BYTE。主函数中         zhen1=&low;zhen2=&high;   rd_temperature(zhen1,zhen2);  temp=low+(high*256);,实际温度还需除以16,因为LS BYTE最低位为0.125。

(八)模数转换:

  核心代码示例:

u8 adc(u8 adress)
{
  u8 mid;
  IIC_Start();
  IIC_SendByte(0x90);
  IIC_WaitAck();
  IIC_SendByte(adress);
  IIC_WaitAck();
  IIC_Start();
  IIC_SendByte(0x91);
  IIC_WaitAck();
  mid=IIC_RecByte();
  IIC_SendAck(1);
  IIC_Stop();
  return mid;
}

初始化后第一步,本单片机中A2A1A0已经为0,写就第0位为0,读时1。

第二步一般是0x43或0x41,可以看之前文章理解。 

 本模块用IIC为底层,sendack函数1是代表接受结束,0代表还想继续接受。stop函数也不可以少。

(九)掉电存储数据

  核心代码展示:

u8 atr()
{
  u8 result;
  IIC_Start();
  IIC_SendByte(0xa0);
  IIC_WaitAck();
  IIC_SendByte(0);
  IIC_WaitAck();
  IIC_Start();
  IIC_SendByte(0xa1);
  IIC_WaitAck();
  result=IIC_RecByte();
  IIC_SendAck(1);
  IIC_Stop();
  return result;
}

 

 

 读和写在这里很清楚,按照顺序来就好,与上同,多个字节写法可以见我以前写的文章。

(10)串口

  核心代码展示:

void open()
{
  EA=1;
  ET0=1;
  ES=1;
}

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
}

void out(u8 *a)
{
  while(*a!='')
  {
    SBUF=*a;
	while(TI==0);
	TI=0;
	a++;
  }
}

void chuankou() interrupt 4
{
   if(RI)
   {
     org[i++]=SBUF;
	 RI=0;
   }
   if(i==8) i=0;
}

 串口也是中断的一种,波特率的计算在STC-ISP中给出,从现在开始,为了避免BUG,各定时器不要重复出现。接收时RI会变成1,接受结束要清零。将要发出的信息写入SBUF,发送完成后TI变成1,发送结束要清零,用while清零。SBUF发送和接受在物理结构上独立,但使用时地址相同。

(11)超声波(前面文章没写,这里多啰嗦一点)

核心代码展示:

u16 flag;
float a;
sbit TX=P1^0;
sbit RX=P1^1;

void Timer1Init(void)		//12.5微秒@12.000MHz
{
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x6A;		//设置定时初值
	TH1 = 0xFF;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 0;		//定时器1关闭计时
}

void me_dis()
{
	u8 num=10;
	flag=0;  
	TX=0;
	TL1=0x6A;
	TH1=0xFF;	
	TR1=1;    
	while(num--)
	{
		while(!TF1);
		TX=TX^1;
		TF1=0;
	}          
	TR1=0;    
	TL1=0;
	TH1=0;    
	TR1=1;    
	while(RX&&!TF1); 
	TR1=0;    
	if(TF1)   
	{
		TF1=0;
		flag=1;
	}
}

void main()
{
	close();
	Timer0Init();
	open();
	Timer1Init();
  while(1)
	{
		if(count>1000)
		{
			count=0;
			me_dis();
			a=((TH1*256+TL1)*0.017/12);
			if(flag==0)
			sprintf(org,"   %02d.%03d",(u16)a,((a-(u16)a)*1000));
			else
			sprintf(org,"%04d%04d",9999,9999);
		}
		translate(org,tran);
	}
}

    首先我们需要满足超声波40kHZ的需求,并且他要求有50%的占空比。对应40kHZ的周期为1/400000,依据占空比为百分之五十,在一个周期之内有一半的时间发送的信号为高电平,有一半的时间发送的信号为低电平,经过单位的换算,我们知道对应的每一次高低电平的时间为12.5微秒,并且要求高低电平来回交换。要精确的达到12.5微秒,光靠延时函数是很难做到的,在单片机内我们可以用定时器来满足较为精准的时间需求。定时器的设置就不讲了,不懂得话看我之前的文章或者STC15用户手册。

    之后就是计算距离的长度,我们知道声音的速度大约为340m/s,假如我们要在数码管上显示的单位为厘米,那么本处换算后就是34000cm/s。距离与速度的关系是x=vt,下面计算物体与单片机的距离,唯一所缺的就是时间。依据上一段所说,在单片机内时间测量较为精准的就是定时器,所以本处我们也可以用定时器来测量声音传播的时间。

    如何计算时间呢?(在下面的程序中我们使用的是定时器1,本处我们就拿定时器1举例)我们可以观察TH1和TL1的变化,如果(TH1<<8)+TL1所构成的16位二进制的数字加1,代表时间经过了1/定时器频率(如果采用12T模式,还需要将定时器的频率除以12),之前提到定时器的读和写的地址是相同的,所以我们只需要将接受到信号时的(TH1<<8)+TL1减去发送信号时的(TH1<<8)+TL1,再将这个数据乘以每次加1的时间我们就可以得到公式中所需要的t。

    最后我们还要注意超声波的发送包括去和回两个过程,所以我们最后算出的距离是去和回的两次路径的总和,所以我们需要将最终的结果除以2。

    

(十二) NE555

核心代码展示:

  void timer_set()
{
	TL0=0xFf-15;
	TH0=0xFF;
	TL1=0xCD;
	TH1=0xD4;
	AUXR|=0x40;
	TMOD|=0x04;
	ET0=1;
	ET1=1;
	EA=1;
	TR1=1;
	TR0=1;
}
之后适当修改主函数并设置两次中段的内容:
void main()
{
	close();
	timer_set();
  while(1)
	{
		sprintf(org,"%08d",(int)frequency*16);
		translate(org,tran);
	}
}

void time_0() interrupt 1
{
	number++;
}

void time_1() interrupt 3
{
	count++;
		if(count==1000)
	{
		frequency=number;
		number=0;
		count=0;
	}
	display(tran,x);
	if(++x==8) x=0;
}

 

NE555是一个信号发生电路,有三个5kΩ的电阻分压,故称555定时器。NE555是一个纯硬件的设计,所以它没有可以编程的部分,唯独可以调节的是图中Rb3的阻值,一旦RB3的阻值确定,那么它的功能也就此确定。NE555没有可以编程的部分。

在我们使用的单面机上,P34与NET SIG相靠近,而定时器0的计数模式可以对P34外部的脉冲进行计数,所以我们将P34和NET SIG相联,用定时器0的计数模式,对NE555发出的信号进行计数,通过这种方式来计算它的频率。

 

好了,所有模块结束,祝比赛顺利!

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/779535.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号