IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 单片机模拟iic从设备-主要代码 -> 正文阅读

[嵌入式]单片机模拟iic从设备-主要代码

1、参照原理《单片机模拟iic从设备-原理说明》使用中断引脚协助SDA脚进行iic起始信号和结束信号的判断。

2、本次代码从机工作在多个从设备的情况下,选择方案一。

? ? ? ? 2.1 本代码涉及到的算法:对于iic发送数据或者发送应答后用到iic超时释放SDA,避免拉死iic、拉死主机。

? ? ? ? 2.2?本代码使用外部中断引脚,考虑iic特性,故外部引脚监测SDA下降沿触发,然后确认是否为iic启动信号,进而进行通信。

? ? ? ? 2.3?如果iic通信速率快的话,单片机处理不过来,会导致错误,本iic时钟为150Khz

? ? ? ? 2.4?基于150khz的时钟,有时单片机会误进入起始信号接收iic地址,从而错过真正的起始信号,本代码加入了接收数据异常后退出iic模式。

? ? ? ? 2.5?单片机接收数据很好,但是发送数据比较慢。注意。

? ? ? ? 2.6 单片机基于松翰SN8P2708A,很老的芯片了。编译器需要用官方提供的开发工具和烧录器。

? ? ? ? 2.7 主设备通信格式为:发送起始信号、发送从设备iic地址、发送1字节数据、发送1字节数据、发送结束信号。对于主发送。对于主读取,发送起始信号、发送从设备iic地址、发送1字节数据、发送0xff、发送结束信号、发送起始信号、发送从设备iic地址、读取数据。

3、iic_drive.h

#ifndef __IIC_DRIVE_H__
#define __IIC_DRIVE_H__

#include "SN8P2708A.h"
#include "typedef.h"

//i2c对应的 GPIO 引脚宏定义P10 P11
#define IIC_SCL	FP10
#define IIC_SDA	FP11

#define iic_sda FP02    //中断引脚外加辅助IIC_SDA输入引脚
#define iic_delay_time 6//最大延迟等待时常为6us,对于时钟频率150Khz

extern uint8_t IIC_ADDR;//由开机上电ADC采集判断IIC_ADDR的地址是多少(8位哈)
extern uint8_t KEY_Value;//按键反馈回来的结果
extern uint8_t led_row_data[10];//led每一行对应的值

#define	device_ID_ADDR  0x6f	//器件的ID地址
#define	device_ID 		0x14	//器件的ID地址值
#define	device_CODE_ADDR 0x70   //器件的软件地址
#define	device_CODE 	0x40	//器件的软件值
#define	device_KEY_ADDR 0x50	//上层读取单片机按键值的地址
#define	device_NO_KEY	0x80	//没有检测到按键按下

这是每一行的按键地址///
#define	Addr_ROW1 0x59
#define	Addr_ROW2 0x5a
#define	Addr_ROW3 0x5b
#define	Addr_ROW4 0x5c
#define	Addr_ROW5 0x5d
#define	Addr_ROW6 0x5e
#define	Addr_ROW7 0x5f
#define	Addr_ROW8 0x60
#define	Addr_ROW9 0x61
#define	Addr_ROW10 0x62


//iic的初始化配置
void iic_init_config(void);

#endif /*__IIC_DRIVE_H__*/

4、iic_deive.c

/*
//以下代码作者:金丝草
//本代码功能:软件模拟iic从设备进行通信
*/

#include "iic_drive.h"
中断函数要是调用函数的话,在函数定义的前面必须加上__interrupt

static uint8_t iic_RX_BUF[3] = { 0 };//iic接收缓存区2个就够了
static uint8_t get_iic_addr=0x00;    //获取到的iic地址
static uint8_t flag = 0;             //设定为全局变量
static uint8_t iic_Count = 8;        //iic的计数器
static uint8_t iic_delay=iic_delay_time;//初始化iic等待时长

//iic初始化配置
void iic_init_config(void)
{
	///iic对应的引脚配置工作模式
	FP10M=0;//时钟配置为输入模式
	FP11M=1;//数据配置为输出模式
	P1OC= 0x03;//P10为开漏模式,P11为开漏模式
	//默认拉高状态
	IIC_SDA = 1;
//	IIC_SCL = 1;//作为输入引脚无需赋值,也付不了值

	//注:P01的中断触发方向为下降沿。是不可更改的哈
	FP02M = 0;  //引脚配置为输入模式
//	P0UR =0x02; //配置为上拉模式//外部有上拉电阻了
	FP02IRQ = 0;//先清除中断标志位
	FP02IEN = 1;//开启外部中断P01使能
	FGIE = 1;   //开启总中断
}


************************此器件工作在iic从模式下*********************************/
void __interrupt [0x08] ISR(void)
{
	static uint8_t temp = 0x01;

	if(IIC_SCL)//表示确实来开始信号了
	{
		FGIE = 0;//关闭所有中断
		get_iic_addr = 0x00;
		while(IIC_SCL);//等待时钟拉低
		for(iic_Count=0x80;iic_Count!=0;iic_Count>>=1)
		{
			while(!IIC_SCL);//等待时钟拉高
			if(iic_sda)
			{
				get_iic_addr |=iic_Count;//将读取的数据保存在缓存区里
				temp = iic_sda;//临时存放SDA的当前值
			}
			if(iic_Count == 0x01)
			{
				break;
			}
			if(temp == 0) //判断是否为IIC结束信号
			{
				while(IIC_SCL)//等待时钟拉低,且判断是否为IIC结束信号
				{
					if(iic_sda == 1)//结束信号来了
					{
						if(IIC_SCL == 1)//再次确认是否为结束信号
							goto exit_iic;//结束本次通信
						else
							break;
					}	
				}
			}
			else
				while(IIC_SCL);//等待时钟拉低
		}
		//比较地址是否为自己且是否为读或写
		if ((get_iic_addr & 0xfe) == IIC_ADDR)//如果接收到的地址匹配了
		{
			//发送ack应答信号//
			while(IIC_SCL);//等待时钟拉低
			IIC_SDA = 0;//发送应答信号
			while (!IIC_SCL)//等待时钟拉高
			{
				iic_delay--;
				if(!iic_delay)
				{IIC_SDA=1;iic_delay=iic_delay_time;goto exit_iic;} //超时等待处理
			}
			iic_delay=iic_delay_time;
			//发送ack应答信号//

			if (get_iic_addr & 0x01)/如果是读单片机
			{
				switch(iic_RX_BUF[0])
				{
				case device_ID_ADDR: temp=device_ID;break;
				case device_CODE_ADDR	:temp=device_CODE;break;
				case device_KEY_ADDR	:temp=KEY_Value;KEY_Value=device_NO_KEY;break;
				}
				for(iic_Count=0x80;iic_Count!=0;iic_Count>>=1)//结束之后时钟是低电平
				{
					while(IIC_SCL);//时钟拉低的话
					if(temp & iic_Count)//判断要发送的数据是高还是低
					{
						IIC_SDA=1;
					}
					else
					{
						IIC_SDA=0;
					}
					if(iic_sda == 0)
					{
						while (!IIC_SCL)//等待时钟拉高
						{
						iic_delay--;
						if(!iic_delay)
						{IIC_SDA=1;iic_delay=iic_delay_time;goto exit_iic;} //超时等待处理
						}
						iic_delay=iic_delay_time;
					}
					else
						while(!IIC_SCL);//等待时钟拉高
				}
				if(iic_sda == 0) //如果最后数据发送的为0
				{
					while(IIC_SCL)//等待时钟拉低
					{
						iic_delay--;
						if(!iic_delay)
						{IIC_SDA=1;iic_delay=iic_delay_time;goto exit_iic;} //超时等待处理
					}
					IIC_SDA = 1;//释放SDA线
					iic_delay=iic_delay_time;
				}
			}
			else/写单片机
			{
				RX_DATA:
				接收数据
				iic_RX_BUF[flag]=0x00;//缓存区清零
				while(IIC_SCL)//等待时钟拉低
				{
					iic_delay--;
					if(!iic_delay)
					{IIC_SDA=1;iic_delay=iic_delay_time;goto exit_iic;} //超时等待处理
				}
				IIC_SDA=1;//释放总线
				iic_delay=iic_delay_time;
				for(iic_Count=0x80;iic_Count!=0;iic_Count>>=1)
				{
					while(!IIC_SCL);//等待时钟拉高
					if(iic_sda)
					{
						iic_RX_BUF[flag] |=iic_Count;//将读取的数据保存在缓存区里
					}
					if(iic_Count==0x01)
					{
						break;
					}
					while(IIC_SCL);//等待时钟拉低
				}
				接收数据

				/发送ack应答信号//
				while(IIC_SCL);//等待时钟拉低
				IIC_SDA = 0;//发送应答信号
				while (!IIC_SCL)//等待时钟拉高
				{
					iic_delay--;
					if(!iic_delay)
					{IIC_SDA=1;iic_delay=iic_delay_time;goto exit_iic;} //超时等待处理
				}
				iic_delay=iic_delay_time;
				发送ack应答信号//				
				if(flag)
				{
					flag=0;
					switch( iic_RX_BUF[0] )//led控制地址及结果
					{
					case Addr_ROW1:  led_row_data[0]=iic_RX_BUF[1]<<2;break;
					case Addr_ROW2:  led_row_data[1]=iic_RX_BUF[1]<<2;break;
					case Addr_ROW3:  led_row_data[2]=iic_RX_BUF[1]<<2;break;
					case Addr_ROW4:  led_row_data[3]=iic_RX_BUF[1]<<2;break;
					case Addr_ROW5:	 led_row_data[4]=iic_RX_BUF[1]<<2;break;
					case Addr_ROW6:	 led_row_data[5]=iic_RX_BUF[1]<<2;break;
					case Addr_ROW7:	 led_row_data[6]=iic_RX_BUF[1]<<2;break;
					case Addr_ROW8:	 led_row_data[7]=iic_RX_BUF[1]<<2;break;
					case Addr_ROW9:	 led_row_data[8]=iic_RX_BUF[1]<<2;break;
					case Addr_ROW10: led_row_data[9]=iic_RX_BUF[1]<<2;break;
					}
					while(IIC_SCL)//等待时钟拉低
					{
						iic_delay--;
						if(!iic_delay)
						{IIC_SDA=1;iic_delay=iic_delay_time;goto exit_iic;} //超时等待处理
					}
					IIC_SDA=1;//释放总线
					iic_delay=iic_delay_time;
				}
				else
				{
					flag=1;
					goto RX_DATA;
				}
			}
		}
	}
	exit_iic:
	FP02IRQ = 0;//中断标志清零
	FGIE = 1;//开启所有中断
}

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-12 23:37:07  更:2021-10-12 23:38:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:40:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码