51单片机学习记录(六)IIC,ADC部分

51单片机差不多就这样了,相关的代码可以看我的gitee,可以减少自己造轮子的痛苦:51单片机学习记录

1、iic部分

前面讲过的关于IIC的原理,可以帮助理解,有对iic不太清楚的可以看下:

stm32配置总结-iic的使用
面试中比较常问的通信协议总结

这里开发板也是接了一个AT24C02来用作IIC实验,这个芯片来做iic学习还是很经典的啊
在这里插入图片描述
这个之前写过stm32相关的文章:stm32配置总结-iic的使用,有需要的可以去查看下。

这里51单片机没有硬件iic,需要我们自己去写软件iic,这里直接参考普中科技的例程:

#include "iic.h"



void iic_start(void)
{
    
    
    IIC_SDA = 1; 
    delay_10us(1);
    IIC_SCL = 1;
    delay_10us(1);
    IIC_SDA = 0; //当SCL为高电平时,SDA由高变为低
    delay_10us(1);
    IIC_SCL = 0; //钳住I2C总线,准备发送或接收数据
    delay_10us(1);
}

void iic_stop(void)
{
    
    
    IIC_SDA = 0; 
    delay_10us(1);
    IIC_SCL = 1;
    delay_10us(1);
    IIC_SDA = 1; //当SCL为高电平时,SDA由低变为高
    delay_10us(1);
}

void iic_ack(void)
{
    
    
    IIC_SCL = 0;
    IIC_SDA = 0; // SDA为低电平
    delay_10us(1);
    IIC_SCL = 1;
    delay_10us(1);
    IIC_SCL = 0;
}

void iic_nack(void)
{
    
    
    IIC_SCL = 0;
    IIC_SDA = 1; // SDA为高电平
    delay_10us(1);
    IIC_SCL = 1;
    delay_10us(1);
    IIC_SCL = 0;
}

u8 iic_wait_ack(void)
{
    
    
    u8 time_temp = 0;

    IIC_SCL = 1;
    delay_10us(1);
    while (IIC_SDA) //等待SDA为低电平
    {
    
    
        time_temp++;
        if (time_temp > 100) //超时则强制结束IIC通信
        {
    
    
            iic_stop();
            return 1;
        }
    }
    IIC_SCL = 0;
    return 0;
}

void iic_write_byte(u8 dat)
{
    
    
    u8 i = 0;

    IIC_SCL = 0;
    for (i = 0; i < 8; i++) //循环8次将一个字节传出,先传高再传低位
    {
    
    
        if ((dat & 0x80) > 0)
            IIC_SDA = 1;
        else
            IIC_SDA = 0;
        dat <<= 1;
        delay_10us(1);
        IIC_SCL = 1;
        delay_10us(1);
        IIC_SCL = 0;
        delay_10us(1);
    }
}

u8 iic_read_byte(u8 ack)
{
    
    
    u8 i = 0, receive = 0;

    for (i = 0; i < 8; i++) //循环8次将一个字节读出,先读高再传低位
    {
    
    
        IIC_SCL = 0;
        delay_10us(1);
        IIC_SCL = 1;
        receive <<= 1;
        if (IIC_SDA)
            receive++;
        delay_10us(1);
    }
    if (!ack)
        iic_nack();
    else
        iic_ack();

    return receive;
}

读写at24c02部分也是:

#include "at24c02.h"

void at24c02_write_one_byte(u8 addr,u8 dat)
{
    
    				   	  	    																 
    iic_start();  
	iic_write_byte(0XA0);	//发送写命令	    	  
	iic_wait_ack();	   
    iic_write_byte(addr);	//发送写地址   
	iic_wait_ack(); 	 										  		   
	iic_write_byte(dat);	//发送字节    							   
	iic_wait_ack();  		    	   
    iic_stop();				//产生一个停止条件
	delay_ms(10);	 
}

u8 at24c02_read_one_byte(u8 addr)
{
    
    				  
	u8 temp=0;		  	    																 
    iic_start();  
	iic_write_byte(0XA0);	//发送写命令	   
	iic_wait_ack(); 
    iic_write_byte(addr); 	//发送写地址  
	iic_wait_ack();	    
	iic_start();  	 	   
	iic_write_byte(0XA1); 	//进入接收模式         			   
	iic_wait_ack();	 
    temp=iic_read_byte(0);	//读取字节		   
    iic_stop();				//产生一个停止条件    
	return temp;			//返回读取的数据
}

这样就可以在主函数中进行读写了。

2、ADC部分

这里51单片机好像也没有ADC的片上外设,所以需要其他的AD模块来实现对应的功能,这里用的是XPT2046这个芯片来实现的,下面来看下这个芯片是如何实现对应的功能的:
在这里插入图片描述
可以看到这个芯片原来是作为触摸屏芯片的,是一个12位的AD,监测范围0到6V。下面是相关的引脚介绍:
在这里插入图片描述
工作模式说明如下:
在这里插入图片描述
单端模式和差分模式的选择方式:(ADC就直接单端模式即可)
在这里插入图片描述
使用IIC等方式可以进行通信,时序图如下所示:
在这里插入图片描述
说明如下:
在这里插入图片描述
其中控制字的命令说明如下:
在这里插入图片描述
最终的代码如下:

#include "adc.h"
#include "intrins.h"

void xpt2046_wirte_data(u8 dat)
{
    
    
    u8 i;

    CLK = 0;
    _nop_();
    for (i = 0; i < 8; i++) //循环8次,每次传输一位,共一个字节
    {
    
    
        DIN = dat >> 7; //先传高位再传低位
        dat <<= 1;      //将低位移到高位
        CLK = 0;        // CLK由低到高产生一个上升沿,从而写入数据
        _nop_();
        CLK = 1;
        _nop_();
    }
}

u16 xpt2046_read_data(void)
{
    
    
    u8 i;
    u16 dat = 0;

    CLK = 0;
    _nop_();
    for (i = 0; i < 12; i++) //循环12次,每次读取一位,大于一个字节数,所以返回值类型是u16
    {
    
    
        dat <<= 1;
        CLK = 1;
        _nop_();
        CLK = 0; // CLK由高到低产生一个下降沿,从而读取数据
        _nop_();
        dat |= DOUT; //先读取高位,再读取低位。
    }
    return dat;
}

u16 xpt2046_read_adc_value(u8 cmd)
{
    
    
    u8 i;
    u16 adc_value = 0;

    CLK = 0;                 //先拉低时钟
    CS = 0;                  //使能XPT2046
    xpt2046_wirte_data(cmd); //发送命令字
    for (i = 6; i > 0; i--)
        ; //延时等待转换结果
    CLK = 1;
    _nop_();
    CLK = 0; //发送一个时钟,清除BUSY
    _nop_();
    adc_value = xpt2046_read_data();
    CS = 1; //关闭XPT2046
    return adc_value;
}

3、DAC部分

这里DAC是通过PWM结合电路来实现的,前面已经介绍过ADC相关的内容,这里不再赘述了,ADC的工作原理如下所示
在这里插入图片描述
使用的电路如下所示,这里我们要实现ADC的功能,只要输出的对应的PWM即可。
在这里插入图片描述

扫描二维码关注公众号,回复: 16112139 查看本文章

猜你喜欢

转载自blog.csdn.net/m0_51220742/article/details/125031928
今日推荐