您的位置:首页 > 娱乐 > 明星 > 常见的网络营销有哪些_深圳建立网站_佛山做seo推广公司_品牌策划公司排名

常见的网络营销有哪些_深圳建立网站_佛山做seo推广公司_品牌策划公司排名

2024/12/23 12:59:16 来源:https://blog.csdn.net/qq_43422073/article/details/143196903  浏览:    关键词:常见的网络营销有哪些_深圳建立网站_佛山做seo推广公司_品牌策划公司排名
常见的网络营销有哪些_深圳建立网站_佛山做seo推广公司_品牌策划公司排名

51单片机快速入门之 模拟 I2C 用精准中断来控制

首先复习一下51单片机快速入门之定时器和计数器(含中断基础)

再看看之前的I2C操作 51单片机快速入门之 IIC I2C通信


定时器/计数器是51单片机中用于实现精确延时的硬件资源。通过配置定时器的初始值和工作模式,可以实现不同长度的延时。

例如,如果使用12MHz晶振,一个机器周期为1μs,可以通过设置定时器的初值来实现精确的延时。

// 假设需要延时1ms              

void delay_1ms()               

{

unsigned int i;               

TMOD |= 0x01; // 设置定时器0为工作方式1

TH0 = 0xFC; // 设置初值,1ms延时     

TL0 = 0x18;                   

TR0 = 1; // 启动定时器            

while(!TF0); // 等待定时器溢出       

TR0 = 0; // 关闭定时器            

TF0 = 0; // 清除溢出标志

        


软件延时是通过循环语句实现的,虽然不如定时器精确,但在不需要极高精度的场合也可以使用。为了提高精度,可以使用_NOP_()函数,它是C51编译器提供的一个空操作指令,执行时间为1个机器周期。

#include <intrins.h>

// 假设需要延时10μs

void delay_10us(unsigned char t)

{

do

{

_nop_(); _nop_(); _nop_(); _nop_(); // 4个_NOP_()指令,共4μs

_nop_(); _nop_(); _nop_(); _nop_(); // 另外4μs

}

while(--t);

}


下面开始写代码:

#include <STC89C5xRC.H>sbit SCL=P2^0;  //时钟线
sbit SDA=P2^1;  //数据线
sbit DQ=P2^4;//读取按键
void delay_2us(); // 延时函数声明
void startI2C();//开始信号
void stopI2C();//停止信号
bit ack; //用于存储ACK信息
void ack_i2c(); //用于处理ACK信息
void SendByte(unsigned char date);//发送字节数据void main()
{startI2C();//开始信号SendByte(0xA2);//发送从机地址ack_i2c();SendByte(0x00);//设置数据需要保存在哪个地方  地址!ack_i2c();SendByte(0X66);//发送 数据ack_i2c();stopI2C();//发送停止信号while(1); // 防止程序重复运行
}void startI2C() //开始信号{SDA=1;  //拉高SDA,delay_2us(); //延时2usSCL=1;  //拉高SCL 初始化delay_2us(); //延时2usdelay_2us(); //延时2usSDA=0;  //拉低SDA 使其进入下降沿delay_2us(); //延时2usSCL=0; //拉低SCL准备接收数据delay_2us(); //延时2usdelay_2us(); //延时2usdelay_2us(); //延时2us}void stopI2C()  //停止信号
{SDA=0; //拉低SDA准备进入上升沿delay_2us(); //延时2usSCL=1;//拉高SCL让其 波形长度领先delay_2us(); //延时2usdelay_2us(); //延时2usSDA=1;delay_2us(); //延时2us/*SCL领先 SDA 此时进入上升沿 占用 现在SCL与SDA波长相等*/}void SendByte(unsigned char date)//发送字节数据
{unsigned char j; //创建一个变量用于传输for(j=0; j<8; j++) {if(date<<j&0x80)/*每次往左移动j 变量位 这里加()是防止意外错误 再 和 0x80 1000 0000 进行与运算AXB  */{SDA=1;      //当其最高位为1时,  结果是1  SDA 拉高} else {SDA=0;   //当其最高位为0时,结果是0 SDA 拉低}delay_2us(); //延时2usSCL=1;//拉高以发送现在SDA状态 到从机delay_2us(); //延时2usdelay_2us(); //延时2usSCL=0;  //拉低开始接收下一个数据delay_2us(); //延时2usdelay_2us(); //延时2usdelay_2us(); //延时2us} SDA=1;//拉高预防因数据最后一位是0 SDA=0 而导致 进入停止信号SCL=1;//拉高以发送现在SDA状态 到从机		SDA=1;//拉高进入ack检测delay_2us(); //延时2usif(SDA==0) { //从机发来ACK响应ack=1;   //表接收到ACK响应    SCL=0;delay_2us(); //延时2usdelay_2us(); //延时2usdelay_2us(); //延时2us} else {stopI2C();}}void ack_i2c()
{if(ack==1) {ack=0;   //满足条件初始化} else {while(1);   //不满足条件阻塞程序不让其往后执行}}void delay_2us()
{TMOD=0x10;//设置使用定时器1    0001 0000  不需要io触发   断开引脚输入 16位模式TH1 = 255; // 因为65534 / 256 = 255   存放高8位  256x256=65536TL1 = 254; // 因为65534 % 256 =      存放低8位  初值计算 255*256+254=65,534/*65536-65534=2 us12MHz 晶振振荡 12分频之后,为1MHz 当其从0-65536 时,需要65536μs 微秒  */EA=1;//打开总中断ET1=1;//允许定时器1中断TR1=1;//打开定时器1while(!TF1);//判断是否溢出/*感叹号 ! 是逻辑非运算符如果 TF1 是 1(定时器1溢出),  则 !TF1 是 0(假)。 向中断发送了请求如果 TF1 是 0(定时器1未溢出),则 !TF1 是 1(真)。一旦 TF1 变为1(溢出),!TF1 就变为0,循环结束*/TR1=0;//关闭定时器1TF1=0;//初始化为未溢出状态}

写入24c02c 运行效果(单字节写入):

  1. 开始信号
  2. 7从机地址和 写入0
  3. 从机回复ACK
  4. 数据存储地址
  5. 从机回复 ACK 
  6. 数据
  7. 从机回复ACK
  8. 停止信号

数据读取代码(选择读取):

  1. 开始信号
  2. 7从机地址和 写入0 伪写操作
  3. 从机回复ACK
  4. 数据存储地址
  5. 从机回复ACK
  6. 开始信号
  7. 7从机地址和 读取1 读取操作
  8. 从机回复ACK
  9. 获取从机发来的8位数据
  10. 拉高SDA 主机发送NACK 
  11. 停止信号
读取数据并控制P1 寄存器 应用 以验证效果 ,代码如下
#include <STC89C5xRC.H>sbit SCL=P2^0;  //时钟线
sbit SDA=P2^1;  //数据线
sbit DQ=P2^4;//读取按键
void delay_2us(); // 延时函数声明
void startI2C();//开始信号
void stopI2C();//停止信号
bit ack; //用于存储ACK信息
void ack_i2c(); //用于处理ACK信息
void SendByte(unsigned char date);//发送字节数据
unsigned char D1,C1;//D1用于发送8位脉冲,C1用于保存读取到的数据
void REI2C();//读取8位函数
void main()
{startI2C();//开始信号SendByte(0xA2);//发送从机地址ack_i2c();SendByte(0x00);//设置数据需要保存在哪个地方  地址!ack_i2c();SendByte(0X66);//发送 数据ack_i2c();stopI2C();//发送停止信号while(DQ==1); //当其为高电平时,表示按钮未按下阻塞程序startI2C();//开始信号SendByte(0xA2);//发送 伪写入从机地址ack_i2c();SendByte(0x00);//设置要读取的 数据存储地址ack_i2c();startI2C();//开始信号SendByte(0xA3);//发送 读取从机地址ack_i2c();REI2C();P1 = 0x00; // 先将 P1 置为 0 P1 = C1;   // 再赋值 ack_i2c();stopI2C();//停止信号while(1); // 防止程序重复运行
}void startI2C() //开始信号{SDA=1;  //拉高SDA,delay_2us(); //延时2usSCL=1;  //拉高SCL 初始化delay_2us(); //延时2usdelay_2us(); //延时2usSDA=0;  //拉低SDA 使其进入下降沿delay_2us(); //延时2usSCL=0; //拉低SCL准备接收数据delay_2us(); //延时2usdelay_2us(); //延时2usdelay_2us(); //延时2us}void stopI2C()  //停止信号
{SDA=0; //拉低SDA准备进入上升沿delay_2us(); //延时2usSCL=1;//拉高SCL让其 波形长度领先delay_2us(); //延时2usdelay_2us(); //延时2usSDA=1;delay_2us(); //延时2us/*SCL领先 SDA 此时进入上升沿 占用 现在SCL与SDA波长相等*/}void SendByte(unsigned char date)//发送字节数据
{unsigned char j; //创建一个变量用于传输for(j=0; j<8; j++) {if(date<<j&0x80)/*每次往左移动j 变量位 这里加()是防止意外错误 再 和 0x80 1000 0000 进行与运算AXB  */{SDA=1;      //当其最高位为1时,  结果是1  SDA 拉高} else {SDA=0;   //当其最高位为0时,结果是0 SDA 拉低}delay_2us(); //延时2usSCL=1;//拉高以发送现在SDA状态 到从机delay_2us(); //延时2usdelay_2us(); //延时2usSCL=0;  //拉低开始接收下一个数据delay_2us(); //延时2usdelay_2us(); //延时2usdelay_2us(); //延时2us} SDA=1;//拉高预防因数据最后一位是0 SDA=0 而导致 进入停止信号SCL=1;//拉高以发送现在SDA状态 到从机		SDA=1;//拉高进入ack检测delay_2us(); //延时2usif(SDA==0) { //从机发来ACK响应ack=1;   //表接收到ACK响应    SCL=0;delay_2us(); //延时2usdelay_2us(); //延时2usdelay_2us(); //延时2us} else {stopI2C();}}void ack_i2c()
{if(ack==1) {ack=0;   //满足条件初始化} else {while(1);   //不满足条件阻塞程序不让其往后执行}}void REI2C()
{  SDA=1;//初始化SDA for(D1=0;D1<8;D1++)
{SCL=1;//读取当前SDA if(SDA==1)
{C1=C1 | 1<<D1; /* |与运算A+B 运行一个循环之后 C1此时为1 0000 0001 1为0000 0001 当 D1=1时 左移一位 0000 0010   
0000 0001 
0000 0010
----------0000 0011 C1此时就为这个值	D1=2时 位移两位 0000 0100 0000 00110000 0100此时C1=0000 0111 注意每次移位都只是 对0000 0001 操作 ! 谨防思维混乱*/
}//因为D1是递增的,所以如果 当D1=2 时 if不满足 下次 D1=3 就会多出一个0 SCL=0;  //拉低开始接收下一个数据delay_2us(); //延时2usdelay_2us(); //延时2usdelay_2us(); //延时2us}
SDA=1;//拉高预防因数据最后一位是0 SDA=0 而导致 进入停止信号SCL=1;//拉高以发送现在SDA状态 到从机		SDA=1;//拉高进入ack检测delay_2us(); //延时2usif(SDA==0) { //从机发来ACK响应ack=1;   //表接收到ACK响应    SCL=0;delay_2us(); //延时2usdelay_2us(); //延时2usdelay_2us(); //延时2us} else {stopI2C();}}void delay_2us()
{TMOD=0x10;//设置使用定时器1    0001 0000  不需要io触发   断开引脚输入 16位模式TH1 = 255; // 因为65534 / 256 = 255   存放高8位  256x256=65536TL1 = 254; // 因为65534 % 256 =      存放低8位  初值计算 255*256+254=65,534/*65536-65534=2 us12MHz 晶振振荡 12分频之后,为1MHz 当其从0-65536 时,需要65536μs 微秒  */EA=1;//打开总中断ET1=1;//允许定时器1中断TR1=1;//打开定时器1while(!TF1);//判断是否溢出/*感叹号 ! 是逻辑非运算符如果 TF1 是 1(定时器1溢出),  则 !TF1 是 0(假)。 向中断发送了请求如果 TF1 是 0(定时器1未溢出),则 !TF1 是 1(真)。一旦 TF1 变为1(溢出),!TF1 就变为0,循环结束*/TR1=0;//关闭定时器1TF1=0;//初始化为未溢出状态}
运行效果!可以看到我们读取到了之前存入的 0x66 数据! 

0110 0110 注意看P1的状态

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com