0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

应广单片机系列——高速I2C接口

聚丰开发 2018-10-16 18:45 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

经过一段时间的慎重考虑,在诸多朋友的支持下,决定在接下来的日子里,会尽可能多的写一些关于应广多核单片机应用的文章,希望能给有兴趣学习了解应广单片机的朋友提供到点滴帮助。

这个针对应广双核、多核单片机应用的系列,会以具体程序为例,在程序中加以注释,只要条件允许,例程都会经过调试,如果只是编译没有调试的,我会注明。

附件中的例程代码,读者可以自由使用,不需要通知我,如有可能,希望在代码中保留我的签名信息,深表感谢!

例程为利用应广单片机的特点,用软件实现理论速率可以达到1M的I2C通讯接口,如果是其它普通单片机,也可以用软件模拟出高速I2C,不同点是应广实现模拟后还能够实现各种控制功能,而其它普通单片则不能。


//-----------------------------------------
//应广单片机软件实现高速I2C接口例程(SALVE模式)
//本例仅供参考,欢迎指正程序中的问题
//本例利用应广单片机的双核特点
//用一个核专门对I2C接口的IO进行扫描等待
//对I2C接口的高低变化利用应广特有的IO状态等待指令高速实现IO口跳变判断
//利用定时器
进行超时判断
//理论上可以让模拟的I2C接口达到1M的速率
//2012年12月15日
//
//作者:戴上举
//邮箱:daishangju@163.com
//博客:forum.eet-cn.com/BLOG_daishangju_334.HTM
//电话:13509678051
//Q Q:1514292225
//-----------------------------------------

.chip p201cs14a
//{{PADAUK_CODE_OPTION
.Code_Option Bootup Slow // 1024 ILRC
.Code_Option LVD 2.79V // Maximum performance = 4 MIPS
.Code_Option Security Enable // Security 3/4 words Enable
//}}PADAUK_CODE_OPTION

//定义I2C接口要用的IO口,用户可以自己修改这里的IO口定义
I2C_SDA equ pa.0
I2C_SDA_LOW equ set0 I2C_SDA
I2C_SDA_HIGH equ set1 I2C_SDA
I2C_SDA_INPUT equ set0 pac.0
I2C_SDA_OUTPUT equ set1 pac.0
I2C_SCL equ pa.4
//定义I2C设备地址,用户可以自己修改此地址
I2C_READ_CMD equ 0x7F
I2C_WRITE_CMD equ 0x7E


word init_timer

//byte Xms
//byte ms_cnt

byte i2c_device //用来存放I2C接口地址
byte i2c_write_byte //I2C进行写操作时存放I2C写入的数据
byte i2c_read_byte //I2C进行读操作时候读出的内容

bit i2c_start_flag

//应广单片机程序入口,第一条必须为跳转到第一个内核主程序入口地址的指令,第二条为第二个内核,有几个内核就有几条
.romadr 0x000
goto main0
goto main1


//应广单片机中断程序入口地址,所有中断共用同一个入口,需要用户自己判断中断类型
.romadr 0x010
pushaf //压栈
if(intrq.T16) //判断是否为定时中断
{
stt16 init_timer //清内部TIMER计数器
if(i2c_start_flag) //启动I2C通讯处理后这个标志会被置1
{
I2C_SDA_INPUT
reset //系统复位
}
}
intrq = 0 //清中断标志
popaf //弹栈
reti //中断返回

//----------------------------------------
//input: ms
//用该函数可以再4M的频率下得到近似1毫秒的延时,在第一个内核中调用中断会导致延时加长
//----------------------------------------
/*delayXms:
while(Xms)
{
wdreset
ms_cnt = 20
while(ms_cnt)
{
delay 195
ms_cnt--
}
Xms--
}
ret*/

//用IO口模拟I2C slave模式的子函数
i2c_slave:
I2C_SDA_INPUT //将SDA设为输入
i2c_start:
//I2C空闲状态下SDA和SCL同为高电平,要启动I2C前初始状态必须是两者同为高
stt16 init_timer //清内部TIMER计数器
if(!I2C_SCL) //如果SCL为低,此时不用启动I2C通讯处理
{
goto i2c_stop
}
if(!I2C_SDA) //如果SDA为低,此时不用启动I2C通讯处理
{
goto i2c_stop
}

i2c_start_flag = 1 //启动I2C通讯处理,这个标志位会在定时中断中用到

//I2C的START信号是SDA和SCL同为高电平装态下SDA先变为低,然后SCL变为低
//判断I2C START信号
//等待SDA从高变低
stt16 init_timer //清内部TIMER计数器
wait0 I2C_SDA //应广特有的等待IO变低指令,等待SDA从高变低,如果长时间没有变低,会触发定时中断,系统复位
nop //加适当延时消除IO抖动的影响
nop
nop
nop
//等待SCL从高变低,原理同上
stt16 init_timer
wait0 I2C_SCL //if overtime MCU will auto reset
nop
nop
nop
nop

//已经判断为得到有效START信号


//开始接收I2C的器件地址,为了实现高速处理,程序顺序处理,没有使用循环处理方式
i2c_device = 0
stt16 init_timer //device bit7
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.7
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit6
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.6
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit5
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.5
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit4
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.4
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit3
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.3
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit2
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.2
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit1
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.1
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit0
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.0
}
wait0 I2C_SCL
//nop //后面的比较操作会耗费时间,可以不用延时
//nop
//nop
//nop


if(i2c_device == I2C_READ_CMD) //I2C进行读操作,同样为了实现高速处理,程序顺序处理,没有使用循环处理方式
{
//回复slave ACK信号
I2C_SDA_OUTPUT
I2C_SDA_LOW
stt16 init_timer
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop


stt16 init_timer //i2c_read_byte bit7
if(i2c_read_byte.7)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit6
if(i2c_read_byte.6)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit5
if(i2c_read_byte.5)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit4
if(i2c_read_byte.4)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit3
if(i2c_read_byte.3)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit2
if(i2c_read_byte.2)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit1
if(i2c_read_byte.1)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit0
if(i2c_read_byte.0)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop

I2C_SDA_INPUT
stt16 init_timer //master ack/nack
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //END
wait1 I2C_SCL
nop
nop
nop
nop
stt16 init_timer
wait1 I2C_SDA
nop
nop
nop
nop
}
else if(i2c_device == I2C_WRITE_CMD) //I2C是进行写操作,同样为了实现高速处理,程序顺序处理,没有使用循环处理方式
{
//slave ACK
I2C_SDA_OUTPUT //--------I2C SDA input/output switch----------
I2C_SDA_LOW
stt16 init_timer
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop

I2C_SDA_INPUT
i2c_write_byte = 0
stt16 init_timer //i2c_write_byte bit7
if(I2C_SDA)
{
set1 i2c_write_byte.7
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit6
if(I2C_SDA)
{
set1 i2c_write_byte.6
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit5
if(I2C_SDA)
{
set1 i2c_write_byte.5
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit4
if(I2C_SDA)
{
set1 i2c_write_byte.4
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit3
if(I2C_SDA)
{
set1 i2c_write_byte.3
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit2
if(I2C_SDA)
{
set1 i2c_write_byte.2
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit1
if(I2C_SDA)
{
set1 i2c_write_byte.1
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit0
if(I2C_SDA)
{
set1 i2c_write_byte.0
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop

//slave NACK
I2C_SDA_OUTPUT //--------I2C SDA input/output switch----------
I2C_SDA_HIGH
stt16 init_timer
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
I2C_SDA_INPUT //--------I2C SDA input/output switch----------
nop
nop
stt16 init_timer //END
wait1 I2C_SCL
nop
nop
nop
nop
stt16 init_timer
wait1 I2C_SDA
//nop
//nop
//nop
//nop

//下面代码用户可根据实际情况进行修改,这里是将I2C写入的数据取反后放到读操作位置
i2c_read_byte = ~i2c_write_byte

}

i2c_stop:
I2C_SDA_INPUT
i2c_start_flag = 0 //I2C stop work

ret

//----------------FPPA0-------------------
main0:


.ADJUST_OTP_IHRCR 8MIPS // IHRC/2 = 8MIPS, WatchDog Disable, RAM 0,1 temporary be used
sp = 0x30

disgint
inten = 0

mov a,0b000_11_111 //disable timer
mov t16m,a

delay 200

clkmd.0 = 0 //pa.5 as GPIO

//注意IO口的输入输出设定
pa = 0b1111_1111
pac = 0b0000_0000
paph = 0b1111_1111
pb = 0b1111_1111
pbc = 0b0000_0000
pbph = 0b1111_1111


init_timer = 7768 //从7768进行校准为100ms
mov a,0b100_11_111
mov t16m,a
stt16 init_timer


delay 200

mov a,0
mov intrq,a

i2c_start_flag = 0 //I2C not start work


// adcdi = 0b0000_0100 //pb2 is analog input
// adcc = 0b10_0010_00 //enable ADC, select pb2
// adcm = 0b000_0100_0 //system clock/16
//adcm = 0b000_0111_0 //system clock/128
set1 fppen.1 //eanble FPPA1
clkmd.1 = 1 //enable watch dog
wdreset //clear watch dog

// Xms = 100
// call delayXms

stt16 init_timer
intrq = 0
inten.T16 = 1 //打开定时中断
engint


main0_loop:
init_timer = 0
wdreset
//用户可以在这里添加自己想要的任意代码,这里可以实现任意一个普通单片机能够是想的功能
goto main0_loop


//----------------FPPA1-------------------
main1:
sp = 0x38
main1_loop:
call i2c_slave
goto main1_loop

程序中的多个NOP可以用DELAY3代替,用DELAY 指令可以节省程序空间

I2C启动判断代码用下面部分更可靠(2012.12.22)

//wait SDA and SCL high at the same time
while((!I2C_SDA) || (!I2C_SCL))
{
stt16init_timer
nop
nop
nop
nop
}


if(!I2C_SDA)
{
gotoi2c_stop
}
if(!I2C_SCL)
{
gotoi2c_stop
}

代码已编译,未调试


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6074

    文章

    45359

    浏览量

    664323
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    CW32单片机I2C接口来读写EEPROM芯片

    一、概述 CW32L083 内部集成 2I2C 控制器,能按照设定的传输速率(标准,快速,高速)将需要发送的数据按照 I2C 规范串行发送到
    发表于 12-09 07:43

    深入剖析I2C协议

    I2C是由Philips开发的简单的双向两线总线,在深入浅出理解SPI协议中,我们区分了单工,半双工,全双工协议数据流向的区别,根据特征,I2C协议属于半双工协议(即同一时刻,数据单向流动)。此外
    的头像 发表于 08-21 15:10 3345次阅读
    深入剖析<b class='flag-5'>I2C</b>协议

    高效率、6通道、白光LED驱动器,带I2C接口 skyworksinc

    电子发烧友网为你提供()高效率、6通道、白光LED驱动器,带I2C接口相关产品参数、数据手册,更有高效率、6通道、白光LED驱动器,带I2C接口的引脚图、接线图、封装手册、中文资料、英
    发表于 07-30 18:31
    高效率、6通道、白光LED驱动器,带<b class='flag-5'>I2C</b><b class='flag-5'>接口</b> skyworksinc

    简单了解I2C接口

    在电子电路的复杂世界里,各种电路模块设备需要相互通信才能协同工作 ,I2C接口就像是电路模块设备间的沟通桥梁,今天就带大家深入了解它。
    的头像 发表于 05-08 14:15 2138次阅读
    简单了解<b class='flag-5'>I2C</b><b class='flag-5'>接口</b>

    I2C总线复用

    帝晶智慧屏I2C总线复用
    的头像 发表于 03-11 17:20 1885次阅读

    单片机I/O接口的传输方式

    单片机(Microcontroller Unit,MCU)作为嵌入式系统的核心部件,其输入输出(Input/Output,I/O)接口是实现与外部设备数据交换的关键。I/O
    的头像 发表于 02-02 15:56 1690次阅读

    I2C总线通信原理 如何设计I2C总线电路

    、高效的通信接口标准。I2C总线通信原理主要包括以下要点: 总线结构 : I2C总线仅使用两条信号线,即串行数据线(SDA)和串行时钟线(SCL)。 SDA线路用于传输实际的数据信息,而SCL线路则用于同步通信的时钟信号。 通信
    的头像 发表于 01-31 15:01 1937次阅读

    I2C总线的优缺点分析

    设备之间的通信,这大大减少了所需的引脚数量,降低了硬件成本。此外,由于其简单性,I2C总线也易于实现和维护。 2. 多主机和多从支持 I2C总线支持多个主机和多个从
    的头像 发表于 01-17 15:50 1811次阅读

    I2C总线与Arduino的接口示例

    在现代电子设计中,I2C总线因其简单性和灵活性而广受欢迎。它允许多个设备共享同一通信线路,从而节省空间和成本。Arduino,作为一个多功能的微控制器平台,自然也支持I2C通信。 I2C
    的头像 发表于 01-17 15:34 2413次阅读

    I2C总线的工作模式介绍

    在现代电子系统中,I2C总线作为一种多主机、多从的串行通信协议,扮演着至关重要的角色。它允许多个设备共享同一总线,进行数据传输,从而简化了系统设计并降低了成本。 I2C总线的基本特性 I2C
    的头像 发表于 01-17 15:32 1679次阅读

    I2C总线与单片机的连接

    在现代电子系统中,单片机(MCU)是核心控制单元,而I2C总线作为一种多主机、多从的串行通信协议,因其简单、高效和节省引脚的特性而被广泛应用于各种电子设备中。 I2C总线概述
    的头像 发表于 01-17 15:18 2034次阅读

    I2C总线应用实例分析

    I2C总线使用两条线进行通信:数据线(SDA)和时钟线(SCL)。这种双线制设计使得I2C总线能够在多个设备之间共享,而不需要为每个设备单独布线。 应用实例:温湿度传感器 假设我们正在设计一个智能家居系统,需要实时监测室内的温湿度。我们选择使用一个带有
    的头像 发表于 01-17 15:09 1279次阅读

    I2C总线与SPI总线的比较

    在现代电子系统中,微控制器与各种外设之间的通信是必不可少的。I2C和SPI是两种流行的串行通信协议,它们各自具有独特的特点和应用场景。 I2C总线 I2C是一种多主机、多从的同步通信
    的头像 发表于 01-17 15:08 1806次阅读

    AN-840: 通过I2C接口更新代码

    电子发烧友网站提供《AN-840: 通过I2C接口更新代码.pdf》资料免费下载
    发表于 01-15 16:04 0次下载
    AN-840: 通过<b class='flag-5'>I2C</b><b class='flag-5'>接口</b>更新代码

    UC-001:MicroConverter I2C兼容接口

    电子发烧友网站提供《UC-001:MicroConverter I2C兼容接口.pdf》资料免费下载
    发表于 01-15 15:51 0次下载
    UC-001:MicroConverter <b class='flag-5'>I2C</b>兼容<b class='flag-5'>接口</b>