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 查看本文章