蓝桥杯-超声波模块,AT24C02,DS18B20,DS1302

 超声波

超声波测距离的原理非常简单,单片机的一个引脚连到发射模块  发出一定频率的信号,此时打开定时器开始计时,如果发射模块发出的声波被物体反射回来,就会在接收端连出的一极产生下降沿,此时读取定时器时间   知道了来回时间和声速,就可以算出距离并显示出来。

     这听起来非常简单明了,所以我在弄这个模块的时候也有点掉以轻心,直接一整份打完,下载调试,结果调试了好长时间。。。

     在这里吸取一点教训,对于没用过的,不熟悉的东西,一定要打一点,测试一下,否则调试的时候,错误的可能性太多,不好找

     我出问题的地方是在发射的频率上,官方给的超声波资料基本没谈怎么用,所以我上网搜了一下,一份资料里说发射频率一般是40khz,我就照办了

     然而我后面仔细看过之后,发现官方板子超声波模块选用的电阻电容和那份资料并不太一样,因此使发射频率上升到了50khz,所以我自然就一直调试不正常。。。

     我是用下降沿触发外部中断,在外部中断里读取时间的,所以连线时要把P3^2和接收端连载一起,接收端在动态数码管上面,具体哪个看原理图。。。

 

DS18B20

控制ds18b20的协议如下:

:初始化

rom操作命令

:存储器操作命令

:执行

 

注:每次使ds18b20执行一次存储器操作命令都得按上面流程来一次,不能连着写两个存储器操作命令

各部分命令看后面参考资料P9.

具体实现: 

        init_ds18b20();//初始化

          Write_DS18B20(0xcc);//0xcc命令,跳过配对rom(因为只有一个)

          Write_DS18B20(0x44);//转换温度命令,最长500ms,如果是不断循环检测就不用delay等待

 

          init_ds18b20();//同上

          Write_DS18B20(0xcc);//同上

          Write_DS18B20(0xbe);//读取存储器命令,从0字节到8字节,0,1是温度值,故下面读两字节就初始化,后面的不需要了

 

          templ=Read_DS18B20();//        先读到低字节

          temph=Read_DS18B20();

          init_ds18b20();

          temp=temph;

          temp<<=8;

          temp|=templ;//以上操作把两个字节整合成一个int型变量temp(keil貌似int16位)

          return temp;


得到了temp之后,只要稍加处理就会变成所需温度的值了

temp为负数,考虑到temp是以补码形式存储,(补码:负数的补码为其正数对应的原码取反加1,例:- 58位补码为+5对应原码00000101取反111110101=11111011. 正数补码为其本身)补码转原码:易知补码首位为1即为负数,为0则正数,如补码11111001,先减1再取反得00000111,考虑到为负数,将首位变为1即得原码(原码首位0,1分别代表正负)

若为正数,直接处理,因为默认为12位精度,16位中有8位代表整数部分,四位为小数部分,还有四位没用,即temp*0.0625(1/16)即得温度值

参考资料:点击打开链接

代码:点击打开链接

 

 

AT24C02

驱动程序照着时序图写或上网找,这里不说了

   24c02是按照i2c通信的,

  在此谈一下鄙人关于i2c的认识:

首先需一个起始信号表示操作开始:先将sdascl均置高(释放总线)再将sda0,即在scl为高时sda低跳变,就是开始信号  顺便把scl拉低。    

开始写一字节:在scl为低时把sda赋好数据,scl上升沿后写过去,再将scl置低,sda装载数据,如此重复,写完8位后,释放总线,等待应答   ,最后把scl

等待ack:等待从件把sda拉低  表示接受成功

读一个字节:先将sda置高(个人理解:若读字节时是下降沿后读到信号,该信号靠从件发出,若主机sda拉低,从件是无力拉高的,因此主机先将sda拉高)此后与写类似,只不过有可能下降沿后读,结束后把scl0

读后也需要释放总线

结束信号:先将sclsda均置低(释放总线,若上述均保证结束时scl0,则不需置scl)再将scl置高,此时sda上升跳变,就是结束信号  

具体实现:

向某个地址写一个数据:

void At24c02Write(uchar addr,uchar dat)
{
    I2C_Start();//起始信号     ·        
          I2C_SendByte(0xa0,1);//器件寻址,1表等待响应,0则略过,另外:器件地址高四位固定为1010,低四位中最低位为写入与读取的选择,
                              //其余三位为器件选择,这里全部接地所以为0
          I2C_SendByte(addr,1);//写入数据的目标地址          
          I2C_SendByte(dat,1);//要写的数据
          I2C_Stop();          //停止信号         ,此后器件进入擦写工作,期间不接受主机的信号
}

向某个地址读一个数据:
<pre name="code" class="cpp">uchar  At24c02Read(uchar addr)
{
    uchar dat=0;
    I2C_Start();//起始信号
          I2C_SendByte(0xa0,1);
          I2C_SendByte(addr,1);//假写入 ,地址即为要读的地址,具体看所含芯片文档
          I2C_Start();//起始信号
          I2C_SendByte(0xa1,1); //最低位变1,设为读取模式
          dat=I2C_ReadByte(); //接受数据
          I2C_Stop();//停止信号
          return dat;
}

接着上次读或写的地址读数据:

uchar  At24c02Read_next()
{
    uchar dat=0;
    I2C_Start();
          I2C_SendByte(0xa1,1);//直接读命令,接着上一次读写的地址读数据
          dat=I2C_ReadByte();
          I2C_Stop();
          return dat;
}          

注意:写入操作后一段时间不能对24c02进行任何操作(正在擦写)   需延时10ms左右

参考资料:点击打开链接i2c,i         2c

代码:点击打开链接

proteus 调试i2c元件的方法

DS1302

驱动程序照着时序图写或上网找(下面也有的下),这里不说了

 

                                 需对DS1302进行的操作

关保护:通过8eH将写保护去掉,这样我们才能将日期,时间的初值写时各个寄存器。

赋初值:对80H82H84H86H88H8AH8CH进行初值的写入。同时也通过秒寄存器将位7CH值改成0,这样DS1302就开始走时运行了。

开保护:将写保护寄存器再写为80H,防止误改写寄存器的值

读数值:不断读取80H8CH的值,将它们格式化后显示出来。

 

<pre name="code" class="html"><pre name="code" class="cpp"><pre name="code" class="objc">uchar write_addr[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
uchar write_data[]={0x00,0x00,0x20,0x16,0x06,0x04,0x16}  ;
uchar read_addr[]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d} ;
uchar read_data[7]={0,0,0,0,0,0,0};
void set_time()
{
uchar write_addr[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
uchar write_data[]={0x00,0x00,0x20,0x16,0x06,0x04,0x16}  ;
uchar read_addr[]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d} ;
uchar read_data[7]={0,0,0,0,0,0,0};
void set_time()
{
    uchar i;
    Ds1302_Single_Byte_Write(0x8e,0x00);//关保护
          for(i=0;i<7;i++)
          {
              Ds1302_Single_Byte_Write(write_addr[i],write_data[i]);//写初值
          }
          Ds1302_Single_Byte_Write(0x8e,0x80);//开保护}
void read_time()
{
    uchar i;
          for(i=0;i<7;i++)
          {
              read_data[i]=Ds1302_Single_Byte_Read(read_addr[i]);//读取 
          }
} <span style="font-family: 宋体, Arial;">                                              </span><span style="font-family: 宋体, Arial;">                                                                 </span><span style="font-family: 宋体, Arial;">    </span>

                                                                                                             关于驱动的一点问题

 

/单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void) 
{
          unsigned char i, dat=0;        
          for (i=0;i<8;i++)
          {         
                    dat = dat >> 1;
                    if (SDA_R)            //if(SDA_R==1)    #define SDA_R SDA /*电平读取*/   
                    {
                               dat |= 0x80;
                    }
                    else 
                    {
                               dat &= 0x7F;
                    }
                    SCK_SET;//时钟置高
                    SCK_CLR;//时钟置低
          } SDA_CLR;//!!!!!!!!!!!!!!!!!!!!!!!!这里有时候不打会显示问号,最好还是把这个数据线拉低
          return dat;
}

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/sinat_30457013/article/details/89383666