第八周 (1)V4T和调度器

考号

prj

new

startup

scr

Driver

Seg.c

Seg.h

User

魔法棒

Output

头文件路径

Led

Led.c

 #include "Led.h"
 ​
 idata unsigned char temp_1=0x00;
 idata unsigned char temp_1_Old=0xff;
 ​
 //ucLed是且只能是0,1
 void Led_Disp(unsigned char* ucLed)
 {
     unsigned char temp;
     
     temp_1=0x00;
     temp_1=(ucLed[0]<<0)|(ucLed[1]<<1)|
     (ucLed[2]<<2)|(ucLed[3]<<3)|
     (ucLed[4]<<4)|(ucLed[5]<<5)|
     (ucLed[6]<<6)|(ucLed[7]<<7);
     
     if(temp_1!=temp_1_Old)
     {
         P0=~temp_1;
         
         temp=P2&0x1f;
         temp=temp|0x80;
         P2=temp;
         temp=P2&0x1f;
         P2=temp;
         
         temp_1_Old=temp_1;
     }
 }
 ​
 void Led_Off()
 {
     unsigned char temp;
     
     P0=0xff;
     
     temp=P2&0x1f;
     temp=temp|0x80;
     P2=temp;
     temp=P2&0x1f;
     P2=temp;
     
     temp_1_Old=0x00;//关掉后我们需要将Old变成关闭
 }
 ​
 idata unsigned char temp_2=0x00;
 idata unsigned char temp_2_Old=0xff;
 ​
 void Beep(bit enable)
 {
     unsigned char temp;
     
     if(enable)
         temp_2|=0x40;
     else
         temp_2&=(~0x40);
     
     if(temp_2!=temp_2_Old)
     {
         P0=temp_2;
         
         temp=P2&0x1f;
         temp=temp|0xa0;
         P2=temp;
         temp=P2&0x1f;
         P2=temp;
         
         temp_2_Old=temp_2;
     }
 }
 ​
 void Motor(bit enable)
 {
     unsigned char temp;
     
     if(enable)
         temp_2|=0x20;
     else
         temp_2&=(~0x20);
     
     if(temp_2!=temp_2_Old)
     {
         P0=temp_2;
         
         temp=P2&0x1f;
         temp=temp|0xa0;
         P2=temp;
         temp=P2&0x1f;
         P2=temp;
         
         temp_2_Old=temp_2;
     }
 }
 ​
 void Relay(bit enable)
 {
     unsigned char temp;
     
     if(enable)
         temp_2|=0x10;
     else
         temp_2&=(~0x10);
     
     if(temp_2!=temp_2_Old)
     {
         P0=temp_2;
         
         temp=P2&0x1f;
         temp=temp|0xa0;
         P2=temp;
         temp=P2&0x1f;
         P2=temp;
         
         temp_2_Old=temp_2;
     }
 }

Led.h

 #include <STC15F2K60S2.H>
 ​
 void Relay(bit enable);
 void Motor(bit enable);
 void Beep(bit enable);
 void Led_Off();
 void Led_Disp(unsigned char* ucLed);

测试main.c

 #include <STC15F2K60S2.H>
 #include "Led.h"
 ​
 pdata unsigned char ucLed[8]={1,0,1,0,1,0,1,0};//全给1和temp_1_Old撞了
 ​
 void main()
 {
     Led_Disp(ucLed);
     Beep(1);
     Motor(1);
     Relay(1);
     while(1)
     {
         
     }
 }

Debug测试,小鹅通31

检测MCU选项

12Mhz

魔法棒Debug,Use,对应COM

配置,烧录,断电重连,开始仿真

Init

Init.c

 #include "Init.h"
 ​
 void System_Init()
 {
     unsigned char temp;
     
     P0=0xff;
     temp=P2&0x1f;
     temp=temp|0x80;
     P2=temp;
     temp=P2&0x1f;
     P2=temp;
     
     P0=0x00;
     temp=P2&0x1f;
     temp=temp|0xa0;
     P2=temp;
     temp=P2&0x1f;
     P2=temp;
 }

Init.h

 #include <STC15F2K60S2.H>
 ​
 void System_Init();
 ​

Seg

Seg.c

 #include "Seg.h"
 ​
 pdata unsigned char Seg_Dula[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
 ​
 void Seg_Disp(unsigned char Wela,unsigned char Dula,bit Point)
 {
     unsigned char temp;
     
     P0=0x00;
     temp=P2&0x1f;
     temp=temp|0xe0;
     P2=temp;
     temp=P2&0x1f;
     P2=temp;
     
     P0=0x01<<Wela;
     temp=P2&0x1f;
     temp=temp|0xc0;
     P2=temp;
     temp=P2&0x1f;
     P2=temp;
 ​
     P0=Seg_Dula[Dula];
     if(Point)
         P0&=0x7f;
     temp=P2&0x1f;
     temp=temp|0xe0;
     P2=temp;
     temp=P2&0x1f;
     P2=temp;
 }

Seg.h

 #include <STC15F2K60S2.H>
 ​
 void Seg_Disp(unsigned char Wela,unsigned char Dula,bit Point);
 ​

测试main.c

 #include <STC15F2K60S2.H>
 #include "Seg.h"
 ​
 pdata unsigned char Seg_Buf[8]={10,10,10,10,10,10,10,10};
 idata unsigned char Seg_Pos=0;
 idata unsigned char Seg_Slow_Down;
 ​
 void main()
 {
     System_Init();
     Seg_Disp(5,2,1);//第六个即第五位显示2,有小数点
     while(1)
     {
         
     }
 }
 ​

ISR

勾选使能定时器中断(定时器1)

 void Timer1_Isr(void) interrupt 3
 {
 }
 ​
 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中断
 }
 ​

中断和测试main.c,顺手补齐Key,Seg,Led_Proc

 #include <STC15F2K60S2.H>
 #include "Led.h"
 #include "Init.h"
 #include "Seg.h"
 ​
 pdata unsigned char ucLed[8]={0,0,0,0,0,0,0,0};
 pdata unsigned char Seg_Buf[8]={10,10,10,10,10,10,10,10};
 idata unsigned char Seg_Pos=0;
 idata unsigned char Seg_Slow_Down;
 ​
 void Key_Proc()
 {
     
 }
 ​
 void Seg_Proc()
 {
     if(Seg_Slow_Down<20)return;
     Seg_Slow_Down=0;
     
     Seg_Buf[0]=1;
     Seg_Buf[1]=2;
     Seg_Buf[2]=3+',';
     Seg_Buf[3]=4;
     Seg_Buf[4]=5+',';
     Seg_Buf[5]=6;
     Seg_Buf[6]=7;
     Seg_Buf[7]=8;
 }
 ​
 void Led_Proc()
 {
     ucLed[0]=1;
     ucLed[1]=0;
     ucLed[2]=1;
     ucLed[3]=0;
     ucLed[4]=1;
     ucLed[5]=0;
     ucLed[6]=1;
     ucLed[7]=0;
     Led_Disp(ucLed);
 }
 ​
 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_Isr(void) interrupt 3
 {
     Seg_Slow_Down++;
     Seg_Pos=(++Seg_Pos)%8;
     //底层没有20的下标(超出上限),加一个',',显示小数点
     if(Seg_Buf[Seg_Pos]>20)
         Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]-',',1);
     else
         Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],0);
 }
 ​
 void main()
 {
     Timer1_Init();
     System_Init();
     while(1)
     {
         Key_Proc();
         Seg_Proc();
         Led_Proc();
     }
 }

关键点

 //底层没有20的下标(超出上限),加一个',',显示小数点
 if(Seg_Buf[Seg_Pos]>20)
     Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]-',',1);
 else
     Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],0);
 Timer1_Init();

Key(很重要)

Key.c

 #include "Key.h"
 ​
 unsigned char Key_Read()
 {
     unsigned char temp=0;
     
     //独立按键
     /*
     if(P33==0)temp=4;
     if(P32==0)temp=5;
     if(P31==0)temp=6;
     if(P30==0)temp=7;
     */
     
     //矩阵键盘
     //测量频率必须注释P34的所有相关
     P44=1;P42=1;P35=1;//P34=1;
     if(P30==0)return 0;//判断是否为串口触发
     
     P44=0;P42=1;P35=1;//P34=1;
     if(P33==0)temp=4;
     if(P32==0)temp=5;
     if(P31==0)temp=6;
     if(P30==0)temp=7;
     
     P44=1;P42=1;P35=1;//P34=1;
     if(P30==0)return 0;
     P44=1;P42=0;P35=1;//P34=1;
     if(P33==0)temp=8;
     if(P32==0)temp=9;
     if((P33==0)&&(P32==0))return 89;
     if(P31==0)temp=10;
     if(P30==0)temp=11;
     
     P44=1;P42=1;P35=1;//P34=1;
     if(P30==0)return 0;
     P44=1;P42=1;P35=0;//P34=1;
     if(P33==0)temp=12;
     if(P32==0)temp=13;
     if(P31==0)temp=14;
     if(P30==0)temp=15;
     
     //频率注释
     /*
     P44=1;P42=1;P35=1;//P34=1;
     if(P30==0)return 0;
     P44=1;P42=1;P35=1;P34=0;
     if(P33==0)temp=16;
     if(P32==0)temp=17;
     if(P31==0)temp=18;
     if(P30==0)temp=19;
     */
     P44=1;P42=1;P35=1;//P34=1;
     P3=P3|0xef;//不影响频率,让P3变为双向口接受
     
     return temp;
 }
 ​

关键点

//测量频率必须注释P34的所有相关
P44=1;P42=1;P35=1;//P34=1;
if(P30==0)return 0;//判断是否为串口触发
//频率注释
/*
	P44=1;P42=1;P35=1;//P34=1;
	if(P30==0)return 0;
	P44=1;P42=1;P35=1;P34=0;
	if(P33==0)temp=16;
	if(P32==0)temp=17;
	if(P31==0)temp=18;
	if(P30==0)temp=19;
	*/
P44=1;P42=1;P35=1;//P34=1;
P3=P3|0xef;//不影响频率,让P3变为双向口接受

Key.h

#include <STC15F2K60S2.H>

unsigned char Key_Read();

双键

if((P33==0)&&(P32==0))return 89;

main.c测试

Debug检测数据

#include <STC15F2K60S2.H>
#include "Key.h"

idata unsigned char Key_Val,Key_Old,Key_Down,Key_Up;
idata unsigned char Key_Slow_Down;

idata unsigned char Key_Down_Data,Key_Up_Data;

void Key_Proc()
{
	if(Key_Slow_Down<10)return;
    Key_Slow_Down=0;
	
	Key_Val=Key_Read();
	Key_Down=Key_Val&(Key_Val^Key_Old);
	Key_Up=~Key_Val&(Key_Val^Key_Old);
	Key_Old=Key_Val;
	
	if(Key_Down!=0)
		Key_Down_Data=Key_Down;
	if(Key_Up!=0)
		Key_Up_Data=Key_Up;
}

void Timer1_Isr(void) interrupt 3
{
	Key_Slow_Down++;
}

void main()
{
	Timer1_Init();
	System_Init();
	while(1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}

ds1302

ds1302.c

 /*  #   DS1302代码片段说明
     1.  本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
     2.  参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
         中对单片机时钟频率的要求,进行代码调试和修改。
 */                              
 #include "ds1302.h"
 #include "intrins.h"
 ​
 sbit SCK=P1^7;
 sbit SDA=P2^3;
 sbit RST=P1^3;
 //
 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);          
 }
 ​
 //写入11:12:13 -> 0x11 0x12 0x13
 void Set_Rtc(unsigned char* ucRtc)
 {
     unsigned char i;
     Write_Ds1302_Byte(0x8e,0x00);//关闭写保护
     Write_Ds1302_Byte(0x80,0x80);//关闭CH,停止计时
     for (i=0;i<3;i++)//时,分,秒
         Write_Ds1302_Byte(0x84-2*i,unRtc[i]/10*16+ucRtc[i]%10);
     Write_Ds1302_Byte(0x8e,0x80);//开启写保护
 }
 ​
 //读取0x11 0x12 0x13 -> 11:12:13
 void Read_Rtc(unsigned char* ucRtc)
 {
     unsigned char i;
     unsigned char temp;
     EA = 0;
     for (i=0;i<3;i++)
     {
         temp=Read_Ds1302_Byte(0x85-2*i);
         unRtc[i]=temp/16*10+temp%16;
     }
     EA = 1;
 }

tips

 void Read_Rtc(unsigned char* ucRtc)
 {
     EA = 0;
     for (i=0;i<3;i++)
     {
         temp=Read_Ds1302_Byte(0x85-2*i);
         unRtc[i]=temp/16*10+temp%16;
     }
     EA = 1;
 }
 Write_Ds1302_Byte(0x84-2*i,unRtc[i]/10*16+ucRtc[i]%10);
 temp=Read_Ds1302_Byte(0x85-2*i);
 unRtc[i]=temp/16*10+temp%16;

ds1302.h

 #include <STC15F2K60S2.H>
 ​
 void Set_Rtc(unsigned char* ucRtc);
 void Read_Rtc(unsigned char* ucRtc);
 ​

数码管只做显示,外设独立

测试和使用

#include <STC15F2K60S2.H>
#include "ds1302.h"

pdata unsigned char ucRtc[3]={11,12,13};
idata unsigned char Time_Slow_Down;

void Seg_Proc()
{
	if(Seg_Slow_Down<20)return;
    Seg_Slow_Down=0;
    
	Seg_Buf[0]=ucRtc[0]/10%10;
	Seg_Buf[1]=ucRtc[0]%10;
	Seg_Buf[2]=10;
	Seg_Buf[3]=ucRtc[1]/10%10;
	Seg_Buf[4]=ucRtc[1]%10;
	Seg_Buf[5]=10;
	Seg_Buf[6]=ucRtc[2]/10%10;
	Seg_Buf[7]=ucRtc[2]%10;
}

void Get_Time()
{
	if(Time_Slow_Down<100)return;
    Time_Slow_Down=0;
    
	Read_Rtc(ucRtc);
}

void Timer1_Isr(void) interrupt 3
{
	Time_Slow_Down++;
}

void main()
{
	System_Init();
	Set_Rtc(ucRtc);
	Timer1_Init();
	while(1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
		Get_Time();
	}
}

ds18b20(onewire)

ds18b20.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;
 }
 ​
 float rd_Temperature()
 {
     unsigned char low,high;
     
     init_ds18b20();
     Write_DS18B20(0xcc);//skip
     Write_DS18B20(0x44);//convert
     
     Delay_OneWire(200);
     
     init_ds18b20();
     Write_DS18B20(0xcc);//skip
     Write_DS18B20(0xbe);//read
     
     low=Read_DS18B20();
     high=Read_DS18B20();
     
     return (float)(high<<8|low)*0.0625;
 }

ds18b20.h

 #include <STC15F2K60S2.H>
 ​
 float rd_Temperature();
 ​

测试

 #include <STC15F2K60S2.H>​
 #include "onewire.h"
 ​
 idata unsigned int Temperature_10x;
 idata unsigned int Temperature_Slow_Down;
 ​
 void Get_Temperature()
 {
     if(Temperature_Slow_Down<300)return;
     Temperature_Slow_Down=0;
     
     Temperature_10x=rd_Temperature()*10;
 }
 ​
 void Timer1_Isr(void) interrupt 3
 {
     Temperature_Slow_Down++;
 }
 ​
 /*
 void Delay750ms(void)   //@12.000MHz
 {
     unsigned char data i, j, k;
     i = 35;
     j = 51;
     k = 182;
     do
     {
         do
         {
             while (--k);
         } while (--j);
     } while (--i);
 }
 */
 ​
 void main()
 {
 //  rd_Temperature();
 //  Delay750ms();
     System_Init();
     Set_Rtc(ucRtc);
     Timer1_Init();
     while(1)
     {
         Key_Proc();
         Seg_Proc();
         Led_Proc();
         Get_Time();
         Get_Temperature();
     }
 }

iic

iic.c

 /*  #   I2C代码片段说明
     1.  本文件夹中提供
     的驱动代码供参赛选手完成程序设计参考。
     2.  参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
         中对单片机时钟频率的要求,进行代码调试和修改。
 */
 #include "iic.h"
 #include "intrins.h"
 ​
 #define DELAY_TIME  5 //10
 ​
 sbit sda=P2^1;
 sbit scl=P2^0;
 //
 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);
 }
 /*
 4->DA
 0x40/0x00 外部输入
 0x41/0x01 光敏输入
 0x42/0x02 差分输入
 0x43/0x03 滑动输入
 */
 unsigned char Ad_Read(unsigned char addr)
 {
     unsigned char temp;
     
     I2CStart();
     I2CSendByte(0x90);//选中pcf,写操作
     I2CWaitAck();
     I2CSendByte(addr);
     I2CWaitAck();
     
     I2CStart();
     I2CSendByte(0x91);//选中pcf,读操作
     I2CWaitAck();
     temp=I2CReceiveByte();
     I2CSendAck(1);
     I2CStop();
     
     return temp;
 }
 ​
 //0~255->0~5
 void Da_Write(unsigned char dat)
 {
     I2CStart();
     I2CSendByte(0x90);//选中pcf,写操作
     I2CWaitAck();
     I2CSendByte(0x41);//写入Da使能
     I2CWaitAck();
     I2CSendByte(dat);//写入数字电压,转化模拟电压
     I2CWaitAck();
 }
 ​
 //写入数组,写入起始位置,写入数据个数(uchar)
 void EEPROM_Write(unsigned char* str,unsigned char addr,unsigned char num)
 {
     I2CStart();
     I2CSendByte(0xa0);//选中AT24C02,写操作
     I2CWaitAck();
     I2CSendByte(addr);//起始地址
     I2CWaitAck();
     
     while(num--)
     {
         I2CSendByte(*str++);//写入每一位数据,指针递增,为下次准备
         I2CWaitAck();
         I2C_Delay(200);//保证完全写入
     }
     I2CStop();
     I2C_Delay(255);
     I2C_Delay(255);
     I2C_Delay(255);
     I2C_Delay(255);
     I2C_Delay(255);
     I2C_Delay(255);
     I2C_Delay(255);
     I2C_Delay(255);
     I2C_Delay(255);
     I2C_Delay(255);
 }
 ​
 //read数组,read起始位置,read数据个数(uchar)
 void EEPROM_Read(unsigned char* str,unsigned char addr,unsigned char num)
 {
     I2CStart();
     I2CSendByte(0xa0);//选中AT24C02,写操作
     I2CWaitAck();
     I2CSendByte(addr);//起始地址
     I2CWaitAck();
     
     I2CStart();
     I2CSendByte(0xa1);//选中AT24C02,读操作
     I2CWaitAck();
     
     EA=0;
     while(num--)
     {
         * str++=I2CReceiveByte();//read每一位数据
         if(num)
             I2CSendAck(0);
         else
             I2CSendAck(1);
     }
     I2CStop();
     EA=1;
 }

tips

#include "iic.h"
#include "intrins.h"

#define DELAY_TIME	5 //10

sbit sda=P2^1;
sbit scl=P2^0;
EA=0;
while(num--)
{
    * str++=I2CReceiveByte();//read每一位数据
    if(num)
        I2CSendAck(0);
    else
        I2CSendAck(1);
}
I2CStop();
EA=1;

iic.h

#include <STC15F2K60S2.H>

unsigned char Ad_Read(unsigned char addr);
void Da_Write(unsigned char dat);
void EEPROM_Write(unsigned char* str,unsigned char addr,unsigned char num);
void EEPROM_Read(unsigned char* str,unsigned char addr,unsigned char num);

测试

万用表测试Da

 #include <STC15F2K60S2.H>
 ​
 #include "iic.h"
 ​
 idata unsigned char Ad_1_Data_10x,Ad_3_Data_10x;
 idata unsigned char AD_DA_Slow_Down;
 ​
 pdata unsigned char EEPROM_Data_W[8]={9,8,7,6,5,4,3,2};
 pdata unsigned char EEPROM_Data_R[8]={0,0,0,0,0,0,0,0};
 ​
 void AD_DA()
 {
     if(AD_DA_Slow_Down<120)return;
     AD_DA_Slow_Down=0;
     
     Ad_1_Data_10x=Ad_Read(0x41)*10/51;
     Ad_3_Data_10x=Ad_Read(0x43)*10/51;
     Da_Write(3*51);
 }
 ​
 void Timer1_Isr(void) interrupt 3
 {
     AD_DA_Slow_Down++;
 }
 /*
 void Delay750ms(void)   //@12.000MHz
 {
     unsigned char data i, j, k;
     i = 35;
     j = 51;
     k = 182;
     do
     {
         do
         {
             while (--k);
         } while (--j);
     } while (--i);
 }
 */
 ​
 void main()
 {
 //  rd_Temperature();
 //  Delay750ms();
     System_Init();
     Set_Rtc(ucRtc);
     EEPROM_Read(EEPROM_Data_R,0,8);
     EEPROM_Write(EEPROM_Data_W,0,8);
     EEPROM_Read(EEPROM_Data_R,0,8);
     Timer1_Init();
     while(1)
     {
         Key_Proc();
         Seg_Proc();
         Led_Proc();
         Get_Time();
         Get_Temperature();
         AD_DA();
         Get_Distance();
     }
 }
 ​

超声波

Ultrasound.c

测的不准换一下延时

练习官方版用注释的延时测得准

 #include "Ultrasound.h"
 #include "intrins.h"
 ​
 sbit US_TX = P1^0;//发射
 sbit US_RX = P1^1;//接收
 ​
 //void Delay12us(void)  //@12.000MHz
 //{
 //  unsigned char data i;
 ​
 //  _nop_();
 //  _nop_();
 //  i = 33;//38
 //  while (--i);
 //}
 ​
 //Y1指令集更准
 ​
 void Delay12us(void)    //@12.000MHz
 {
     unsigned char data i;
 ​
     _nop_();
     i = 3;
     while (--i);
 }
 ​
 void Ut_Wave_Init()
 {
     unsigned char i;
     EA=0;
     for(i=0;i<8;i++)
     {
         US_TX=1;
         Delay12us();
         US_TX=0;
         Delay12us();
     }
     EA=1;
 }
 ​
 //v=340m/s=34000cm/s=0.034cm/us
 //s=v*t/2=0.017t cm
 unsigned char Ut_Wave_Data()
 {
     unsigned int time;
     CMOD = 0X00;
     CH = CL = 0;
     Ut_Wave_Init();
     CR=1;
     while((US_RX==1)&&(CF==0));//没有接收且计数没有溢出
     CR=0;
     //接收到回波
     if(CF==0)
     {
         time=CH<<8|CL;
         return (time*0.017);
     }
     //溢出
     else
     {
         CF=0;
         return 0;
     }
 }

tips

 延时在三个(38,33,3)里切换,正常测距应该有100

Ultrasound.h

 #include <STC15F2K60S2.H>
 ​
 unsigned char Ut_Wave_Data();
 ​

debug

 #include <STC15F2K60S2.H>
 ​
 #include "Ultrasound.h"
 ​
 idata unsigned char Distance;
 idata unsigned char Distance_Slow_Down;
 ​
 void Get_Distance()
 {
     if(Distance_Slow_Down<150)return;
     Distance_Slow_Down=0;
     
     Distance=Ut_Wave_Data();
 }
 ​
 void Timer1_Isr(void) interrupt 3
 {
     Distance_Slow_Down++;
 }
 ​
 /*
 void Delay750ms(void)   //@12.000MHz
 {
     unsigned char data i, j, k;
     i = 35;
     j = 51;
     k = 182;
     do
     {
         do
         {
             while (--k);
         } while (--j);
     } while (--i);
 }
 */
 ​
 void main()
 {
 //  rd_Temperature();
 //  Delay750ms();
     System_Init();
     Set_Rtc(ucRtc);
     EEPROM_Read(EEPROM_Data_R,0,8);
     EEPROM_Write(EEPROM_Data_W,0,8);
     EEPROM_Read(EEPROM_Data_R,0,8);
     Timer1_Init();
     while(1)
     {
         Key_Proc();
         Seg_Proc();
         Led_Proc();
         Get_Time();
         Get_Temperature();
         AD_DA();
         Get_Distance();
     }
 }
 ​

频率NE555

定时器0

使用P34

//测量频率必须注释P34的所有相关

特别注意:跳线帽连接sig和P34

 #include <STC15F2K60S2.H>
 ​
 idata unsigned int Freq;
 idata unsigned int Time_1s;
 ​
 void Timer0_Init(void)      //1毫秒@12.000MHz
 {
     AUXR &= 0x7F;           //定时器时钟12T模式
     TMOD &= 0xF0;           //设置定时器模式
     TMOD |=0x05;//开启计数器模式,且不自动重装
     TL0 = 0x00;             //设置计数初始值
     TH0 = 0x00;             //设置计数初始值
     TF0 = 0;                //清除TF0标志
     TR0 = 1;                //定时器0开始计时
 }
 ​
 void Timer1_Isr(void) interrupt 3
 {
     if(++Time_1s==1000)
     {
         Time_1s=0;
         Freq=(TH0<<8)|TL0;
         TH0=TL0=0;
     }
 }
 ​
 /*
 void Delay750ms(void)   //@12.000MHz
 {
     unsigned char data i, j, k;
     i = 35;
     j = 51;
     k = 182;
     do
     {
         do
         {
             while (--k);
         } while (--j);
     } while (--i);
 }
 */
 ​
 void main()
 {
     //顺序不能轻易改变
 //  rd_Temperature();
 //  Delay750ms();
     System_Init();
     Set_Rtc(ucRtc);
     
     EEPROM_Read(EEPROM_Data_R,0,8);
     EEPROM_Write(EEPROM_Data_W,0,8);
     EEPROM_Read(EEPROM_Data_R,0,8);
     
     Timer0_Init();
     Timer1_Init();
     while(1)
     {
         Key_Proc();
         Seg_Proc();
         Led_Proc();
         Get_Time();
         Get_Temperature();
         AD_DA();
         Get_Distance();
     }
 }
 ​

Pwm

about

 idata unsigned char Pwm_Period;//累积对比
 idata unsigned char Pwm_Compare=6;//比较值,亮度
 void Key_Proc()
 {
     if(Key_Slow_Down<10)return;
     Key_Slow_Down=0;
     
     Key_Val=Key_Read();
     Key_Down=Key_Val&(Key_Val^Key_Old);
     Key_Up=~Key_Val&(Key_Val^Key_Old);
     Key_Old=Key_Val;
     
     if(Key_Down==4)
         Pwm_Compare=(++Pwm_Compare)%10;
 }
 void Led_Proc()
 {
     ucLed[0]=1; 
     ucLed[1]=0;
     ucLed[2]=1;
     ucLed[3]=0;
     ucLed[4]=1;
     ucLed[5]=0;
     ucLed[6]=1;
     ucLed[7]=0;
     //Led_Disp(ucLed);
 }
 ​
 void Timer1_Isr(void) interrupt 3
 {
     Seg_Slow_Down++;
     Key_Slow_Down++;
     
     Time_Slow_Down++;
     Temperature_Slow_Down++;
     AD_DA_Slow_Down++;
     Distance_Slow_Down++;
     
     Seg_Pos=(++Seg_Pos)%8;
     //底层没有20的下标(超出上限),加一个',',显示小数点
     if(Seg_Buf[Seg_Pos]>20)
         Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]-',',1);
     else
         Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],0);
     
     if(++Time_1s==1000)
     {
         Time_1s=0;
         Freq=(TH0<<8)|TL0;
         TH0=TL0=0;
     }
     
     //Pwm
     Pwm_Period=(++Pwm_Period)%10;
     if(Pwm_Period<Pwm_Compare)
         Led_Disp(ucLed);//不调光放在Led_Proc
     else
         Led_Off();
 }

tips

 //Pwm
 Pwm_Period=(++Pwm_Period)%10;
 if(Pwm_Period<Pwm_Compare)
     Led_Disp(ucLed);//不调光放在Led_Proc
 else
     Led_Off();

Uart

串口波特率计算器

定时器2,12T,9600,12M

Uart.c

 #include "Uart.h"
 #include "stdio.h"
 ​
 void Uart1_Init(void)   //9600bps@12.000MHz
 {
     SCON = 0x50;        //8位数据,可变波特率
     AUXR |= 0x01;       //串口1选择定时器2为波特率发生器
     AUXR &= 0xFB;       //定时器时钟12T模式
     T2L = 0xE6;         //设置定时初始值
     T2H = 0xFF;         //设置定时初始值
     AUXR |= 0x10;       //定时器2开始计时
     ES = 1;             //使能串口1中断
     EA=1;
 }
 ​
 extern char putchar(char ch)
 {
     SBUF=ch;
     while(TI==0)
         ;
     TI=0;
     return ch;
 }

Uart.h

 #include <STC15F2K60S2.H>
 ​
 void Uart1_Init(void);  //9600bps@12.000MHz
 ​

mian.c相关代码及其测试

 #include <STC15F2K60S2.H>
 #include "Uart.h"
 ​
 #include "string.h"
 #include "stdio.h"
 ​
 idata unsigned char Uart_Rx_Index;
 pdata unsigned char Uart_Rx_Buf[10]={0,0,0,0,0,0,0,0,0,0};
 idata unsigned char Uart_Rx_Flag;
 idata unsigned char Uart_Rx_Tick;//超时解析计时器
 ​
 void Key_Proc()
 {
     if(Key_Slow_Down<10)return;
     Key_Slow_Down=0;
     
     Key_Val=Key_Read();
     Key_Down=Key_Val&(Key_Val^Key_Old);
     Key_Up=~Key_Val&(Key_Val^Key_Old);
     Key_Old=Key_Val;
     
     if(Key_Down==4)
         Pwm_Compare=(++Pwm_Compare)%10;
     if(Key_Down!=0)
         printf("Key_Down:%bu",Key_Down);//发送
 }
 ​
 void Uart_Proc()
 {
     unsigned char x,y;
     if(Uart_Rx_Index==0)return;
     if(Uart_Rx_Tick>=10)
     {
         Uart_Rx_Flag=0;
         Uart_Rx_Tick=0;
         
         printf("%s",Uart_Rx_Buf);//回显,确保预期接收和真实接收一致
         if(sscanf(Uart_Rx_Buf,"(%bu,%bu)",&x,&y)==2)
             printf("\r\nI Get x=%bu,y=%bu\r\n",x,y);
         else
             printf("\r\nERROR\r\n");
         
         memset(Uart_Rx_Buf,0,Uart_Rx_Index);
         Uart_Rx_Index=0;
     }
 }
 ​
 void Timer1_Isr(void) interrupt 3
 {
     if(Uart_Rx_Flag)
         Uart_Rx_Tick++;
 }
 ​
 void Uart1_Isr(void) interrupt 4
 {
     if (RI)             //检测串口1接收中断
     {
         Uart_Rx_Flag=1;
         Uart_Rx_Tick=0;//重置计数器
         Uart_Rx_Buf[Uart_Rx_Index++]=SBUF;
         RI = 0;         //清除串口1接收中断请求位
         if(Uart_Rx_Index>10)
         {
             Uart_Rx_Index=0;
             memset(Uart_Rx_Buf,0,10);
         }
     }
 }
 ​
 void main()
 {
     //顺序不能轻易改变
     System_Init();
     Set_Rtc(ucRtc);
     
     EEPROM_Read(EEPROM_Data_R,0,8);
     EEPROM_Write(EEPROM_Data_W,0,8);
     EEPROM_Read(EEPROM_Data_R,0,8);
     
     Timer0_Init();
     Uart1_Init();
     Timer1_Init();
     while(1)
     {
         Key_Proc();
         Seg_Proc();
         Led_Proc();
         Get_Time();
         Get_Temperature();
         AD_DA();
         Get_Distance();
         Uart_Proc();
     }
 }

help可以查bu

先检测一下printf,(用key),回显

正常后再把注释掉的Uart_Proc()开起来测试

串口是debug不了的

调度器版本

替换Slow_Down

 idata unsigned long int uwTick;
 ​
 void Timer1_Isr(void) interrupt 3
 {
     uwTick++;
 }
 ​
 typedef struct
 {
     void(*task_func)(void);
     unsigned long int rate_ms;
     unsigned long int last_ms;
 }task_t;
 ​
 idata task_t Scheduler_Task[]={
     {Led_Proc,1,0},
     {Key_Proc,10,0},
     {Seg_Proc,20,0},
     {Get_Time,100,0},
     {Get_Temperature,300,0},
     {AD_DA,150,0},
     {Get_Distance,120,0},
     {Uart_Proc,10,0},
 };
 ​
 idata unsigned char task_num;
 ​
 void Scheduler_Init()
 {
     task_num=sizeof(Scheduler_Task)/sizeof(task_t);
 }
 ​
 void Scheduler_Run()
 {
     unsigned char i;
     for(i=0;i<task_num;i++)
     {
         unsigned long int now_time=uwTick;
         if(now_time>=(Scheduler_Task[i].rate_ms+Scheduler_Task[i].last_ms))
         {
             Scheduler_Task[i].last_ms=now_time;
             Scheduler_Task[i].task_func();
         }
     }
 }
 ​
 void main()
 {
     //顺序不能轻易改变
     System_Init();
     Set_Rtc(ucRtc);
     
     EEPROM_Read(EEPROM_Data_R,0,8);
     EEPROM_Write(EEPROM_Data_W,0,8);
     EEPROM_Read(EEPROM_Data_R,0,8);
     
     Timer0_Init();
     Scheduler_Init();
     Uart1_Init();
     Timer1_Init();
     while(1)
     {
         Scheduler_Run();
     }
 }
 

详细代码解析见模块笔记

Seg.c
P0=0xff;