第九周学习笔记

DS1302

定义引脚和引入头文件(ds1302.c)

 #include "intrins.h"//官方底层用到了nop
 sbit SDA = P2^3;//DS1302_IO
 sbit RST = P1^3;//DS1302_CE
 sbit SCK = P1^7;//DS1302_SCK

关键配置位说明(ds1302.c)

  1. WP写保护位(地址0x8e)置1时,芯片禁止写入操作;置0时,才能进行时间配置

  2. CH时钟停止位(地址为0x80-位于秒寄存器的最高位)置1时,停止时钟振荡器;置0时,启动时钟

时间参数写入流程(ds1302.c)

 void Set_Rtc(unsigned char *ucRtc)
 {
     unsigned char i;
     Write_Ds1302_Byte(0x8e,0x00);//关闭写保护
     Write_Ds1302_Byte(0x80,0x80);//停止时钟振荡器
     for(i=0;i<3;i++)//写入时间时,锁存器地址,秒-0x80,分-0x82,时-0x84
         Write_Ds1302_Byte(0x84 - 2 * i,ucRtc[i] / 10 % 10 * 16 + ucRtc[i] % 10);//写入BCD数据。转换为十六进制
     //BCD码转换公式十进制数值——高4位(十位)*16 + 低4位
     Write_Ds1302_Byte(0x8e,0x80);//重新启用写保护
 }

时间参数读取流程(ds1302.c)

 void Read_Rtc(unsigned char *ucRtc)
 {
     unsigned char i;
     unsigned temp;
     EA = 0;//关闭全局中断保证事需完整性
     for(i-0;i<3;i++)//读取时间时,锁存器地址,秒-0x81,分-0x83,时-0x85
     {
         temp = Read_Ds1302_Byte(0x85 - 2 * i);//读取地址自动递增
         ucRtc[i] = temp / 16 * 10 + temp % 16;//BCD转十进制:高4位*10+低4位
     }
     EA = 1;//恢复中断
 }

NE55(频率)

定时器0相关操作(main.c)

 //定时器0,12MHz,16位(不自动重载),定时器时钟12T(千万不能开中断)
 void Timer0_Init(void)      //1毫秒@12.000MHz
 {
     AUXR &= 0x7F;           //定时器时钟12T模式
     TMOD &= 0xF0;           //设置定时器模式
     TMOD |= 0x01;           //设置定时器模式
     TL0 = 0x18;             //设置定时初始值
     TH0 = 0xFC;             //设置定时初始值
     TF0 = 0;                //清除TF0标志
     TR0 = 1;                //定时器0开始计时
 }
 ​

修改后(实现计数)

 void Timer0_Init(void)      //1毫秒@12.000MHz
 {
     AUXR &= 0x7F;           //定时器时钟12T模式
     TMOD &= 0xF0;           //设置定时器模式
     TMOD |= 0x05;           //设置定时器模式     定时器0这边是0101,但不能影响定时器1
     TL0 = 0x00;             //设置定时初始值     TL0、TH0全用  0ms
     TH0 = 0x00;             //设置定时初始值     TL0、TH0全用  0ms
     TF0 = 0;                //清除TF0标志
     TR0 = 1;                //定时器0开始计时
 }
 ​

数据读取(main.c)

 unsigned int time_all_1s;
 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
 {
     if(++time_all_1s == 1000)
     {
         time_all_1s = 0;
         Freq = TH0 << 8 | TL0;//TH0取高8位
         TH0 = TL0 = 0;//取完之后归0
     }
 }

注意事项

  1. 初始化顺序问题:必须先初始化定时器0,在初始化定时器1

  2. 第一次测量结果误差:让数码管1秒之后在显示,定义一个bit型变量,1秒之后bit置1,在显示

     bit show_flag_first = 0;
     void Seg_Proc()
     {
         if(show_flag_first)
         {
             //进行频率显示
         }
     }
     void Timer1_Isr(void) interrupt 3
     {
         if(++time_all_1s == 1000)
         {
             show_flag_first = 1;
             time_all_1s = 0;
             Freq = TH0 << 8 | TL0;//TH0取高8位
             TH0 = TL0 = 0;//取完之后归0
         }
     }
    
  3. 接线问题:跳线帽接P34和SIGNAL

  4. 按键问题:屏蔽P34

超声波

定义引脚(ultrasound.c)

 sbit Tx = P1^0;//US_TX
 sbit Rx = P1^1;//US_RX

换算

d = 0.017t(d的单位cm,t的单位us)

40kHz 一个周期1/40k=25us

延时函数(ultrasound.c)

 //12us的延时函数
 void Delay12us(void)    //@12.000MHz
 {
     unsigned char data i;
 ​
     _nop_();
     i = 3;
     while (--i);
 }
 ​

发送8个40kHz的方波(ultrasound.c)

 void Ut_Wave_Init()
 {
     unsigned char i;
     for(i=0;i<8;i++)
     {
         Tx = 1;
         Delay12us();
         Tx = 0;
         Delay12us();
     }
 }

数据接收与转换(ultrasound.c)

 unsigned char Ut_Wave_Data()
 {
     unsigned char time;
     //选择定时器pca 
     CH = CL = 0;//类似于定时器0,TH0 = TL0 = 0;
     CMOD = 0X00;//16位不自动重载计时器,类似于定时器 TMOD = 0x00;
     
     EA = 0;
     Ut_Wave_Init();
     EA = 1;
     
     CR = 1;//类似于定时器0 TR0 = 1;发送完成后,开始计时
     while(Rx && !CF);//CF类似于定时器0 TF0;等待我们收到回应(收到回应后Rx=0)或者计数溢出(溢出后CF=1)
     CR = 0;
     if(!CF)
     {
         time = CH << 8 | CL;//时间读取
         return (0.017 * time);
     }
     else//计数溢出
     {
         CF = 0;
         return 0;
     }
 }

串口

串口初始化(Uart.c)

 //串口1(通用)、12MHz、9600波特率、8位数据、定时器2(16位自动重载)、12T
 //加上ES=1、EA=1开启串口中断和总中断
 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;
     EA = 1;
 }

串口重定向(Uart.c)

 #include "stdio.h"//引用头文件,调用putchar函数
 extern char putchar(char ch)
 {
     SBUF = ch;
     while(TI == 0);//发送成功后TI = 1;
     TI = 0;
     return ch;
 }
 ​
 //应用
 unsigned char my_data = 5;
 printf("%bu",my_data)

串口中断接收(main.c)

 pdata unsigned char Uart_Buf[10] = 0;//串口接收缓冲区
 idata unsigned char Uart_Rx_Index;//串口接收索引
 idata unsigned char Uart_Recv_Tick;//串口接收时间标志
 idata unsigned char Uart_Rx_Flag;
 ​
 void Uart1_Isr(void) interrupt 4
 {
     //若接收到数据
     if (RI)             //检测串口1接收中断
     {
         Uart_Rx_Flag = 1;   //接收标志
         Uart_Recv_Tick = 0;//清零接收时间标志
         Uart_Buf[Uart_Rx_Index++] = SBUF;//将数据保存到缓冲区
         RI = 0;         //清除串口1接收中断请求位
     }
     if(Uart_Rx_Index > 10)
     {
         Uart_Rx_Index = 0;//防止溢出
         memset(Uart_Buf,0,10);
     }
 }
 ​
 //定时器1
 void Time1_Isr(void) interrupt 3
 {
     if(Uart_Rx_Flag)
         Uart_Recv_Tick++;
 }

串口处理函数(main.c)

 void Uart_Proc()
 {
     if(Uart_Rx_Index == 0)
         return;//无数据,直接驳回
     if(Uart_Recv_Tick >= 10)//若接收超时,对数据读取,清空缓存区
     {
         Uart_Recv_Tick = 0;
         Uart_Rx_Flag = 0;
         //处理函数
         meset(Uart_Buf,0,Uart_Rx_Index);//清空接收数据
         Uart_Rx_Index = 0;
     }
 }

添加头文件(main.c)

 #include "string.h"