骑IC看MCU

  • 2020-04-29
  • 发表了日志: TI - MCU - MSP430使用指南4 -> PMM&SVS 电源管理监控模块

  • 发表了主题帖: TI - MCU - MSP430使用指南4 -> PMM&SVS 电源管理监控模块

    此内容由EEWORLD论坛网友骑IC看MCU原创,如需转载或用于商业用途需征得作者同意并注明出处 MSP430中Power Management Module (PMM) 和Supply Voltage Supervisor (SVS) 负责内核电压的生成和监控,同时根据不同的模式可以设置相应的初始化方式。 首先分析一下PMM和SVS功能: 根据MSP430 MCU资料或者其他厂商MCU资料我们可以发现,对于3.3V电源的MCU的供电电压都是1.8V – 3.6V这个电压范围。其实对于MCU内核,是需要一个稳定的电压的,因此内部会集成一个LDO用于生成Vcore,也就是核电压。具体电压分配如下: DVCC位输入给MCU的一级电源,电压在1.8V – 3.6V,一般都是采用3.3V供电。 然后内部LDO会将DVCC作为输入,通过一个LDO生成核心电压Vcore,这个Vcore核心电压主要给三块提供电源: CPU: 用于CPU内部的核心计算。 Memory:包含RAM核FRAM(当然,如果是Flash的MCU,还需要一个charge pump)。 数字模块:包括内部串行协议模块,定时器,RTC灯模块 而对于GPIO及Analog资源,直接采用DVCC供电(当然对于ADC或需要高精度电源的模块,会有AVCC电源供电)。   如上图所示,为内部PMM&SVS模块的内部结构框图,输入电源为DVCC,内部经过一堆寄存器的配置后,针对每种模块,分配不同的电源。 下面我们来看一下SVS即电源监控模块。MCU内部会对DVCC电源进行监控,当掉电时会产生复位,也就是所谓的BOR(Brownout reset)。如下图所示BOR有一定的滞环特性,因此需要看时电压降低到了一定的值,还是上升到了一定的值。当电压降低到SVSh_IT-时会触发BOR,当电压从低点回升到SVSh_ITY+时,BOR才能恢复正常。 下图是上电时的SVS复位情况。当给MCU供电时,SVS功能默认开启,在开始状态DVCC电压没有上升到SVSh_ITY+时,复位会一直使能,MCU不会工作。当DVCC电压上升到期望电压后,BOR会释放,启动MCU,开始运行程序。 正常工作模式下,SVS就是一个监控电压的模块,但是我们还需要考虑一种情况:LPM3.5和LPM4.5模式,在这两个模式下,CPU内核电压都失能了,因此RAM中数据也会丢失,故在从LPMx.5H唤醒后也是SVS复位启动,不过这里会有相应的标志来判断时上电复位还是退出LPMx.5复位。 当然对于BOR和POR,也可以通过软件产生,往对应寄存器里写相应的值就可以实现这个功能,具体可以看下面的寄存器介绍。 同时PMM模块内部还有一个高精度的参考电压,可以用作芯片内部其他模块的使用,比如ADC。具体怎么配置,可以看寄存器的介绍。 下图为PMM&SVS模块的所有寄存器介绍,总共包含录歌机损其,三个PMM控制寄存器,一个PMM中断寄存器,一个PMM中断标志寄存器,还有最后一个Power模式寄存器。了解完后你就会发现,如果你的系统不出现BOR, POR灯复位或者不正常的复位影响,你仅仅能使用到PM5CTL0寄存器就好,其他寄存器可以直接忽略,默认就好。   PMMCTL0 : PMMPW:写这个寄存器的密码,这里必须同时写入0x96,才能修改寄存器内其他位。 SVSHE:SVS高电压监控边的使能,默认情况下 一直使能,但是你可以设置成在一些LPM模式下失能。 PMMREGOFF:内部的电压调节器 就是LDO是否在LPM3/4模式下关闭。 PMMSWPOR:软件产生POR位,写1产生一次POR。 PMMSWBOR:软件产生BOR位,写1产生一次BOR。   PMMCTL1 :   这个寄存器是预留的,目前没什么使用,可能在不同系列的MCU中有不同的用法。这里我所给出的是FR2xx_FR4xx的MCU寄存器。   PMMCTL2 : REFBGRDY:Bandgap相关寄存器 只读,这个MCU内部会自动调节状态 REFGENRDY: Bandgap相关寄存器 只读。 BGMODE: Bandgap相关寄存器 只读。 REFBGACT: Bandgap相关寄存器 只读。 REFBGENCAT: Bandgap相关寄存器 只读。 REFBGEN: bandgap电压生成触发位,写1的话 开始触发生成bandgap电压。 REFGEN: 内部参考电压生成触发位,写1的话 开始触发生成内部参考电压。 REFVSEL: 内部参考电源电压选择。 TSENSORN: 温度传感器的使能。MSP430内部集成了一个温度传感器,可以实时监控die的温度,获取方法是使能这个温度传感器,然后使能ADC模块并将ADC模块的输入口设置成内部传感器,即可以获取到内部温度传感器的数据。   PMMIE : 这个寄存器是预留的,目前没什么使用,可能在不同系列的MCU中有不同的用法。这里我所给出的是FR2xx_FR4xx的MCU寄存器。   PMMIFG:   PMMLPM5IFG : 这个标志寄存器就是前面所说的复位时判断是否从LPMx.5产生的。 SVSHIFG:标志Reset是否是由于SVSH引起的。 PMMPOROFG:标志Reset是否是由于软件POR引起的。 PMMRSTIFG :标志Reset是否是由于复位引脚引起的。 PMMBOROFG:标志Reset是否是由于软件BOR引起的。 这个标志寄存器里分别有相应的位表明复位的原因,用于LPM模式或者分析复位源使用。   PM5CTL0:   LPM5SM:LPM3.5模式的切换相关寄存器,不同的device有所区别。 LPM5SW:LPM3.5模式的切换相关寄存器。 LOCKLPM5:锁定GPIO为高阻态,默认情况下是LOCK的,为了正常使用GPIO功能,程序中需要置0。   综上所示,大致讲解了一下MSP430的PMM&SVS模块,其实我们在使用过程中很少用到这一块的知识,这一块的寄存器也直接默认即可。但有一个点是必须要的,就是LOCKLPM5这个寄存器位。操作如下: PM5CTL0 &= ~LOCKLPM5; 这条语句必须要有的,否则你会发现MCU的所有GPIO口都不能正常工作,处于高阻态。 PS:这个主要是针对FRAM工艺的,Flash好像是没有这一位的,具体的话 看使用的devce的datasheet。 还可能使用到的就是PMMIFG中断标志寄存器了,不过都是用来读出出来判断复位源的。  

  • 2020-04-28
  • 发表了主题帖: TI - MCU - MSP430使用指南34 -> USS 模块

    此内容由EEWORLD论坛网友骑IC看MCU原创,如需转载或用于商业用途需征得作者同意并注明出处   USS模块,即Ultrasonic sensing syolution, 超声波感知模块。这个资源设计主要面向表类市场,主要是水表和气表,因为目前的水表,气表等大多采用机械式的方式,但是损耗,精度,量程等都很难满足现在发展的需求,故USS模块借助这先进的理论及算法,在水表和气表方面表现很突出,下分别针对水表和气表两个方面对USS模块进行分析。 目前MSP430集成USS模块的MCU有MSP430FR6047(面向水表),MSP430FR6043(面向气表及水表,主要针对气表)。 Section 1:使用MSP430FR6047去设计智能水表。 先看一下FR6047的资源及内部功能介绍: 先看一下资源框图,主要的模块也就是多路一个USS Subsystem,同时内部会有LEA子系统,主要用于USS相关的算法计算。 首先,我们分析一下超声波检测的原理: 超声波检测,和测距原理差不多,都是基于声波在空气/水中的传播为基础的,如下图所示,在通水的管道中如下安装: 常用安装方式如上图四种,探头和接收模块在一器,因此会有两个探头T12和T21,T12发送声波,T21去感知,然后T21发送声波,T12去感知,通过这种方式便可以计算出管道内的流速,从而计算水量。理论分析如下: 换能器(也即是探头,将电能转换成声波,或者将声波转换成电信号,因此叫换能器)1和换能器2与管道成一定角度相对放置,图中V为流体的流速,∅是换能器安装过程中与管道的夹角,D为管道的内直径,L是两个换能器的距离,C为声波在介质中的传播速度。则根据上图所示,可以得到以下公式:   然后进行公示的转换可以得到下面的公式: 好了,到这一步,我们也就把超声波测距的原理及我们需要去测量的变量计算出来了。 首先对于公式中Area这一部分,就是个常数,跟实际管道的尺寸,安装有关系,所以这一块不需要我们考虑。我们需要测量的就是相对飞行时间delta T和绝对飞行时间T12和T21了。 后面将正式进入USS模块的使用讲解了。由于USS模块个MCU内部其他资源不相同,因为这个模块比较难,内部寄存器配置等和实际测量出来的效果相关度很大,同时如何根据发送的超声波及接受到的回波去计算绝对飞行时间和相对飞行时间需要算法的配合,因此TI提供了一个GUI上位机,同时这个GUI可以根据配置生成MSP430的软件程序,直接能给出绝对飞行时间和相对飞行时间。因此本此讲解不会介绍USS寄存器级别的配置程序,而是讲解如何使用TI提供的资源去开发自己的水表、气表产品。 首先,你需要一个TI的MSP430 EVM板:EVM430-FR6047 就这个卵样子的一块板子,上面包含了下载器电路,串口电路,LCD电路,超声波信号调理电路等,反正一句话,有了它,配合上换能器,你就能放飞自我去测量水的流速和流量。 接上面一句话,换能器? 什么东东。也就是超声波的探头了,不过是收发一体的,长这个样子: 一种压电陶瓷产品,注意 这个东东 有技术含量呦,不是每家公司做出来的都能有很好的精度和一致性的,想了解关于换能器的技术细节,夸克去吧,我也不会。。。。 然后呢,在有了这两个宝贝之后,按照下图所示连接,下图中将两个换能器放在管道内了。 这样就搭建好了我们实验的硬件条件,EVM板,换能器,那么首先我们来分析以下这个EVM板主要的电路图吧。附上详细的电路图连接: http://www.ti.com/lit/zip/slar139 其他电路都比较简单,主要是最小系统电路及LCD显示灯,我们这里主要讲两块电路: 与上位机GUI通信 这一块也比较简单,但是这里注释一点,如下图所示,与PC端连接是使用的USB接口,但是MSP430FR6047与上位机通信支持I2C接口和UART接口,因为中间使用了一个HID bridge。你在板子上可以看到J1接口处,利用跳线帽可以选择使用哪个接口,但是 注意 强烈建议你使用I2C接口,因为速度快,稳定,如果你使用UART接口的话,可能后面会出现ADC波形不能实时更新的情况,而且这个UART口TI说可以使用,但是我研究发现内部去当程序可能有点bug,因此,使用I2C接口,使用I2C接口,使用I2C接口,重要的事情说三遍。 超声波的发送接收电路 如上图所示这一快是USS测量电路,CH_OUT接了一个200R电阻后驱动换能器,CH_IN则需要接一个电容接到换能器上,目的是为了隔离直流信号。USSXOUT和USSXIN需要接一个晶振,这里推荐8MHz,后面再GUI中需要配置。 硬件环境搭建完知乎,我们开始准备软件方面的工作,软件方面主要包括两块:上位机GUI和Code,这两块TI都是提供的。连接如下: http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/USSSWLib/USSSWLibWater/latest/index_FDS.html 在这个页面中,你能看到两个内容: GUI(USSSWLib)  和 Code 把这两个下载下来进行安装,安装正常后可以看到以下两个内容: GUI : 这个就是上位机应用了,用来我们调试修改参数使用的   CODE: 这个是TI提供的程序,可以在CCS或者IAR编译环境中进行编译,其中包含一些Lib文件,即只能使用,不能看源文件。 注意一个点:安装GUI时需要JAVA JRE 1.7以上的环境支持,没安装的给安装以下,连接如下: https://www.java.com/en/download/ 同时CODE也需要CCS及IAR相应版本才能正常导入编译,下图中给的信息可以在GUI安装后的文件夹中一个html网址文件看到,具体和版本不同也不相同,因此具体看你使用的哪个版本。 首先,为了连接GUI,需要先对EVM中的FR6037下载程序,程序在安装后的以下路径: 下载工具可以使用CCS指定下载文件或者UniFlash.然后进行上位机的连接操作: 在option中选择FR6047 水表,然后OK。 再点击Communications中的connect,如下图所示,下面有这个标记表明连接成功。这时你就可以对MCU内部参数进行配置和调试了。 下面我们来分析以下每个参数代表的意思: Transmit frequency: 换能器工作频率,一般水表的再1MHz这个时换能器的参数。 Gap between pulse start and ADC capture: 从发送脉冲波到开启ADC采样的时间。 Number of Pulses: 发送的脉冲个数,这个脉冲是去启动换能器去发送超声波信号的。 UPS and DNS Gap: 通道1发送 到通道2发送之间的间隔。 UPS0 to UPS1 Gap: 一个通道发送脉冲波的时间间隔。 GUI Based Gain Control: 基本放大增益,MCU内部有一个可调的放大器,用于放大接收到的回波信号的。 Meter Constant: 水表常数,就是前面原理中所计算的那个Area常数,这个建议大家还是通过测试得到,因为计算的太理想化,误差较大。 然后让我们看第二页:Advanced Parameters 这一块里面也有一堆参数,但是我就不每个都讲了,大家可以从这个链接中看到每个参数的含义:  这个文件 :C:\ti\msp\USS_02_30_00_03\USS\docs\UserGuide\UserGuide\ch_config.html PS:可能根据你安装的位置不同,有所区别。 说一下主要的参数: USSXT:就是前面硬件电路中提到的接的晶振频率,8000KHz = 8MHz Signal Sampling Frequency : ADC的采样频率,采样频率越高 波形越详细,但是占用内存越大,默认即可。 Capture Duration : ADC采样的时间,这个和脉冲数有关系,如果脉冲数多了 这个需要放大一点,保证能猜到完成的回波形状。 其他的参数无非是一些算法选择,零漂设置,启动ADC PGA时间等一堆,建议大家 直接默认。 参数配置完之后,可以看到下面五个按键: Request Update :讲参数更新到MCU中 Save Configuration :保存参数 Load Configuration :加载参数 Reset Values :复位参数设置 Generate Headers:生成头文件 这些里面可能需要讲的一个就是生成头文件了,点击后,你会发现生成了下面三个文件,这三个文件起始就是你配置的参数,讲这三个文件替换掉CODE中相应的文件 编译下载就可以更新到MCU内部了。 下面我们说一下GUI其他界面: 如下图所示是Waveforms界面,可以实时显示绝对飞行时间和相对飞行时间以及水的流量。 点击进入ADC Capture界面,这个界面比较关键,这个显示的额就是接收到的超声回波,这个波形的好坏决定了检测的精度。如下图所示: 这个波形就比较好,显示了T1发送T2接收和T2发送T1接收的波形,一般情况下纵坐标需要在几百以上,这样有利于算法检测。可以看出,得到的回波,首先是换能器起振最后完全震荡起来,最后关闭的过程,利用这个过程,我们就可以计算绝对飞行时间和相对飞行时间了。 其他的界面,使用到的频率比较低,我就不介绍了,大家有兴趣的话,可以在GUI及CODE这两个安装目录中找到相关的网页文件。PS:推荐大家看官方文件,比较详细而且权威。 下面 我们讲以下这个USS测量模块的算法思想: TI的EVM-FR6047计算出来的流量精度很高,高于目前市场上的几块相似产品,核心有两块: FR6047单芯片解决方案,讲很多超声波发送接收电路集成到了芯片中,稳定,精度高。 算法:求解相对飞行时间的算法较为精确。(这一块具体实现是lib文件,源程序不对外开放,但是用户可以使用) 首先,求绝对飞行时间,也就是T12和T21,就是发送超声波开始计时,收到超声波回波后结束计时,记录下这个时间差,核心载入如何检测到回波,这个TI算法采用检测回波包络的方法,一般检测到包络的峰值点50%即可认为检测到了回波。这个算法很正常,中规中矩。 其次,对于相对飞行时间,delta T = T12 – T21,如果使用上面计算出来的T12和T21带进去计算,会导致出现累计误差,精度较低,因此TI采用了相似性计算的方法去计算这个delta T。 如上图所示,收到两个回波后,首先先对回波进行处理,拟合三角函数关系,然后讲两个回波进行相似度计算,找到最大相似的点,这个时刻两个波形的横坐标只差即可得到相对飞行时间。 好了,MSP430FR6047的水表解决方案的大致内容已经全部描述完了,总结一下: 你需要EVM-FR6047板子,换能器,硬件 你需要安装GUI COD程序 在GUI上进行参数设置(一般默认就行),然后可以生成头文件,替换到code中的文件,编译下载就可以开发自己的产品 最后一句建议,关于这些 有哪些不懂的 第一反应要去查看GUI和CODE安装目录,里面有好几个网页文件,网页里信息很多,讲的很详细,而且很权威,总的一句话 官方文件比什么第三方都好! Section 2:使用MSP430FR6043去设计智能气表。 上面对MSP430FR6047使用方法讲的比较详细了,FR6043方法基本相同,不同点我会着重讲一下,其他步骤直接参考FR6047的水表配置。EVM430-FR6043 首先软件需要下载的: http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/USSSWLib/USSSWLibGas/latest/index_FDS.html GUI : 和FR6047一样的。 CODE Link :http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/USSSWLib/USSSWLibGas/latest/exports/UltrasonicGasFR6043_02_30_00_01_windows_installer.exe 硬件板子呢,长这个样子: 连上气表换能器之后呢,是这个样子: 讲一下区别: FR6043内部的超声波USS模块支持扫频功能,何为扫频功能呢:也就是给换能器驱动的频率在变化,有个范围,可以在GUI中设置,这个也就是为什么FR6043既能做水表也能做气表的原因。因为超声波在空气总衰减比较快,所以固定频率的话 效果较差,当然了,也有内部USS设计的区别,不仅仅是这个点。 主要区别:硬件电路图:http://www.ti.com/lit/pdf/tidrys5 我们只看超声波发送采集这一块: 你会发现,虽然有两路通道CH0和CH1,但是实际电路中使用了模拟开关切换的,仅仅使用了CH0,估计这个是处于一致性的考虑吧,这样能保证驱动两个换能器和接收波形是电路走线一致,减少误差吧。   其次使用上位机时 也有点区别:如下图所示,这里要选用F1 to F2 Sweep,即扫频功能,一般气表换能器的工作频率时200KHz和500KHz,因此针对200KHz的可以设置成180-220扫频。   然后其次就是在生成头文件过程中,生成的文件不再是水表那种三个文件,好像没有三个,具体看实际结果吧,不够最后操作都是一样的,替换掉CODE中对应的文件,编译下载到MCU中。   PS : 附上一些问题的解决方法: ADC波形不对:看看换能器正负有没有接反,波形有多大,换能器有没有起振,用示波器测一下驱动波形看看是否正确。 得不到正确的TOF:参数配置,参数配置,不能乱配,在安装目录里有网页文件描述每个参数的范围,同时每个参数之间也有协调,比如脉冲数和采样时间。 ADC波形:这个有三个变量:发送到采样时间间隔,脉冲数,采样时间。根据波形判断哪个参数不合适,这个分析起来很简单。 连接不上GUI,看看程序有没有下载错,板子上I2C先有没有接,GUI中MCU类型及表的类型有没有选错。 LCD不显示:这个程序中关闭了LCD显示,因此不显示正常,你可以自己修改程序开启。

  • 发表了日志: TI - MCU - MSP430使用指南34 -> USS 模块

  • 2020-04-26
  • 加入了学习《为JTAG通信设置UCD3138》,观看 为JTAG通信设置UCD3138

  • 2020-04-20
  • 加入了学习《PMBus 简介》,观看 1.2 TI PMBus 简介课程(一)

  • 加入了学习《PMBus 简介》,观看 1.1 TI PMBus 简介课程

  • 加入了学习《将JTAG与UCD3138配合使用》,观看 将JTAG与UCD3138配合使用:使用CCS JTAG Flash GUI下载程序

  • 加入了学习《将JTAG与UCD3138配合使用》,观看 将JTAG与UCD3138配合使用:Uniflash简介

  • 2020-04-16
  • 加入了学习《双向 DC-DC 变换器拓扑的对比与设计》,观看 UCD3138 控制方案

  • 加入了学习《双向 DC-DC 变换器拓扑的对比与设计》,观看 拓扑比较

  • 加入了学习《双向 DC-DC 变换器拓扑的对比与设计》,观看 应用概览

  • 2020-03-16
  • 加入了学习《TI Zigbee 3.0及多协议解决方案 》,观看 TI Zigbee 3.0及多协议解决方案 (4)

  • 加入了学习《TI Zigbee 3.0及多协议解决方案 》,观看 TI Zigbee 3.0及多协议解决方案 (3)

  • 加入了学习《TI Zigbee 3.0及多协议解决方案 》,观看 TI Zigbee 3.0及多协议解决方案 (2)

  • 加入了学习《TI Zigbee 3.0及多协议解决方案 》,观看 TI Zigbee 3.0及多协议解决方案 (1)

  • 2020-01-17
  • 发表了主题帖: TI - MCU - MSP430使用指南3 -> SYS系统控制

    此内容由EEWORLD论坛网友骑IC看MCU原创,如需转载或用于商业用途需征得作者同意并注明出处   MSP430 MCU的内部系统控制主要包括以下几块: 上电及复位控制 中断管理 MCU运行模式 TLV数据 对于MSP430的系统控制吧,如果仅仅是站在应用层的角度来说,可以不用太怎么了解,毕竟使用起来的话,SYS模块的的寄存器直接默认就好啦,不会有什么问题,基本都是存在比较深的解决不了的问题时才会牵扯到这一块的内容,因此我的讲解也比较有限,主要说一些关键的内容吧(主要是 我了解的也不是特别深。。。。)。下面开始进入我们今天的分享: 上电及复位管理 BOR:Brownout Reset,也就是掉电复位。 POR:Power on Reset,上电复位。 PUC:Power up Clear,通电清除 这三个有什么区别呢?为什么TI要设计三个复位模式呢?下面首先来看一下内部的复位结构图。 可以看到,BOR的影响最大,其次是POR,再其次是PUC,也就是说只要产生了BOR复位,那么肯定会生成POR复位和PUC复位。如果产生了POR复位,那么肯定会生成PUC复位但不一定会生成BOR复位。那么哪些条件下会产生响应的复位呢? 对于BOR: 设备上电 RST/NMI引脚出现低电平,进入复位模式 从LPM3.5或LPM4.5模式下唤醒 SVS电压监控模块出现了低,也就是内核电压再规定范围外。(SVS内容请参见指南4) 软件BOR事件 对于POR: BOR产生 软件POR事件 对于PUC: BOR或POR产生 看门狗定时时间到 看门狗定时器密码写入错误 FRAM写密码错误(FRAM内容请参见指南9) PMM写密码错误(PMM内容请参见指南4) 其他外围条件 PS:有些不同的芯片 这个条件不一样的,具体哪些条件需要看芯片的datasheet和user guide。 那么这三个不同的复位由不同的条件产生,那么产生后的结果是什么呢: RST/NMI引脚设置成RST模式 所有I/O设置成通用I/O中的输入引脚模式 其他外设初始化,这个初始化成什么模式需要看外设寄存器中复位后的状态 状态寄存器SR复位 看门狗开启并初始化成Active模式 PC指针指向复位中断向量0x0FFFE处,开始执行boot code (PS:多说一点,在MCU上电开始正常执行程序之前,最初是在复位中断向量处的,执行boot code程序,这一块程序是MCU在生产时就固化在MCU内部的程序,这一块程序主要负责搬运程序到RAM中,初始化一些参数等) 那么看起来,这三种复位模式产生后对MCU动作都是一样的,那么为什么要这样设置呢? 放心TI工程师肯定不会闲着无聊做没有意义事情,那么原因就在PMM模块上,PMM模块四MSP430可以做到30nA功耗的核心了,就是这个电源管理(请参见指南4),其实在这里BOR,POR和PUC的区别就是会有不同的标志位,BOR和POR标志位时PMMBORIFG和PMMPORIFG,PUC的产生条件很多,因此要根据每个模块去看,基本在每个模块中都有PUC产生的标志。 那么,就知道啦,当复位后,我们就可以通过检查寄存器的值来确定复位源,从而执行不同的操作,比如保存数据呀,记录复位原因呀等等。 中断管理 学习过微型计算机基础的可能都很熟悉这一块,中断管理嘛,本质上就是一个优先级问题。首先分为可屏蔽中断和不可屏蔽中断,不可屏蔽中断NMI肯定是优先级最高的,只要产生这个中断,那么不论MCU在做什么,立马停下来响应这个中断。其他的则可以使能响应中断,也可以失能。当遇到两个中断情况,则要看这两个中断的优先级来决定了,中断服务程序的响应过程也是比较简单的,入栈PUSH和出栈POP嘛,所以MCU会有一个中断向量表,对应着每个中断的入口地址。 MSP430 MCU不支持硬件上设置中断优先级的,有ICC模块的除外,有ICC模块的时可以设置优先级的。 比如下图时MSPFR2355的中断优先级:(PS:FR2355是有ICC模块的,可以设定比较优先级)   MCU运行模式 先上一个比较乱的运行模式切换图,如上图所示,什么复位呀,LPM模式呀,Active模式呀等等,如何切换到呀,哪些模块运行呀,比较乱,下面稍微讲解一下。 MSP430 MCU之所以能做到超低功耗,主要就是有多种低功耗模式LPM,每种模式下关闭不同的时钟或者资源,甚至时CPU,以实现降低功耗的效果,但是关闭这些资源的时候,肯定会留响应的唤醒机制,如下表所示: SCG0和SCG1时在SR状态寄存器里的时钟生成标志位(参考指南2)。还有OSC晶振,CPU等,主要就是通过不同的模式下关闭不同的资源,其中LPM3.5/LPM4.5模式是在LPM3/LPM4模式的基础上关闭特定的点实现的,功耗最低,当然在使用过程中也要时刻注意着唤醒的方法和唤醒时间。 如何退出,或者进入指定的LPM模式可以参见user guide,不过使用起来其实就是两条语句: __bis_SR_register(LPM0_bits | GIE);                   // Enter LPM0 w/ interrupts __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 但是使用起来你会发现只有LPM0_bits, LPM1_bits , LPM2_bits , LPM3_bits, LPM4_bits,那么如何进入LPM3.5和LPM4.5模式呢? 如下是进入LPM3.5模式下的程序:(其实就是进入LPM3的基础上关闭PMM) PMMCTL0_H = PMMPW_H;                    // Open PMM Registers for write PMMCTL0_L |= PMMREGOFF;                 // and set PMMREGOFF __bis_SR_register(LPM3_bits | GIE); 注意,从LPM3.5模式下唤醒,肯定是会从复位模式开始的,不过有响应的标志位给用户用来确定是LPM3.5唤醒导致的复位。 LPM4.5模式类似: PMMCTL0_H = PMMPW_H;                // Open PMM Registers for write PMMCTL0_L |= PMMREGOFF;             // and set PMMREGOFF PMMCTL0_H = 0;                      // Lock PMM Registers __bis_SR_register(LPM4_bits | GIE); 唤醒后也是从Reset中断向量开始执行。 TLV数据 TLV是个什么东西呢? 其实就是一个保存MCU内部一些信息的数据,包括MCU的代号,Die的位置等,当然还有一些校准的数据供用户使用,比如ADC的校准数据,CS的校准数据等。如下图所示: 如上图所示,是MSP430FR2355的TLV数据,可以看到里面包含的基本信息和ADC,DCO的校准信息。

  • 发表了日志: TI - MCU - MSP430使用指南3 -> SYS系统控制

  • 发表了日志: TI - MCU - MSP430使用指南14 -> I2C通信(eUSCI)

  • 发表了主题帖: TI - MCU - MSP430使用指南14 -> I2C通信(eUSCI)

    此内容由EEWORLD论坛网友骑IC看MCU原创,如需转载或用于商业用途需征得作者同意并注明出处   说到MSP430 MCU的I2C资源,那么首先就得先看一下USCI。 如果你了解过多款MSP430 MCU你会发现,内部资源里有USCI和eUSCI,那么他们什么意思呢? USCI (Universal Serial Communication Interface),即通用串行通信接口,eUSCI中的e则是enhanced的意思,即增强型,那么有什么区别呢? 一些主要的区别如下表所示,F2xx这一列代表USCI,FR57xx代表eUSCI 更多详细区别,请查看TI官方文档: http://www.ti.com/lit/an/slaa522a/slaa522a.pdf 其实你会发现 区别不是很大,仅仅是寄存器的名字变了一点,在使用起来很是相似,因此本次使用eUSCI进行讲解。 eUSCI又分两种:A和B,有什么区别呢: A:支持UART和SPI B:支持I2C和SPI 也就是说两种都支持SPI,但A仅支持UART和SPI,B仅支持I2C和SPI。想过为什么吗? (这段内容比较深,也不一定是全部都是正确的:我认为毕竟eUSCI就是数字逻辑电路嘛,TI设计成这种格式去给客户机会去选用SPI或I2C/UART,相对于单独设计I2C,SPI,UART内核来说,第一节省电路,可以降低功耗和成本,第二减少引脚数量。那为什么都支持SPI嘛,因为SPI协议简单嘛,没有I2C那种起始位,停止位,也没有UART那种固定的波特率,SPI自己有自己的时钟,所以内部电路集成方面与UART或I2C有一定的公共成分,而UART和I2C差别较大,结合起来没什么性价比吧,所以出现了A版本和B版本。这些仅是我的猜测。。。em……) 好啦,那么正式进入我们今天的主题  à I2C协议。 首先,第一部分肯定要讲清楚什么是I2C协议,这类资料网上一大堆一大堆,也可以很容易的搜索到资料来参考,我就简单的过一下吧。 I2C(Inter-Integrated Circuit) 是Philips公司发明的一种用于片级连接的总线方式,有什么好处呢: 简单,就两根线SDA和SCL。 总线方式,可以挂接多个设备。 通信速度有低速,普通,高速等模式,目前最快好像可以实现3.4Mbps速度。 其实还有挺多优点的,不然也不可能经历那么多年I2C依旧很主流。首先我想稍微解释一下挂接设备数量问题: 这个可以挂接多个设备主要是由于I2C的开漏特性决定的,即0有效,外部需要上拉电阻,开漏和推挽的资料网上也很多,可以自己查来看看。那么能挂接多少设备呢?这个本质上是由总线上的容性决定的,我们都知道,电容越大,充电时间越长,那么信号上升速度越满,当慢到不能满足I2C要求是,那么则不能挂接了,挂接设备相当于并联电容嘛,电容就变大了,然后就。。。,就。。。。 I2C协议如下: 简单吧,就两根线嘛,首先呢,起始位。如果你是个Master,需要发信号给Slave,那么肯定要给个起始位嘛,告诉Slave你开始发数据了,如上图:SCL=1,SDA由0变1标志着起始位,然后呢,肯定是要写地址了,从设备地址,总线上挂接了很多Slave,你要发送给谁呢? 那么就写谁的地址,I2C地址是7位的(别抬杠,知道有10位地址模式,不过原理相同的),然后呢,下一位是R/W,你是读Slave里的数据呢,还是写数据到Slave呢?需要吧? 后面就是数据了,当然,当你写完一个数据后,Slave会给你个回应那个,then你接着写,Slave再回应,就这样最后Master发送一个STOP位(SCL=1,SDA由低变高),好啦,那么一包数据通信即结束了。 PS:讲解一个小知识:你细看I2C协议你会发现:SDA数据线上只能再SCL=0的时候改变,SCL=1时需要保持状态,为什么呢? 简单嘛,请看START和STOP信号,你就知道了。 好啦,I2C协议讲解完了,那么正式进入正题:MSP430 I2C如何使用: 先上一张I2C模块的内部结构图: 一堆一堆的寄存器,标志位对吧,最终出来两根线SDA和SCL是吧。就是这样的嘛,内部的模块不就是一些逻辑电路加一些Memory嘛,迷糊没事的,后面看看寄存器就知道了: 那么就开始讲解如何使用吧,也就是寄存器内容啦: 看一下有哪些寄存器: UCBxCTLW0   UCA10:10位地址选择,1时为10位地址模式,0时为7位地址模式。 UCLSA10:Slave10位地址选择,也就是说你作为Master时需要通信的Slave是否是10位地址的模式。 UCMM:多Master选择,因为正常I2C时钟是由Master控制的,因此如果存在多Master时,需要释放SCL的,故设计了这一位用来应对多Master模式。 UCMST:Master或Slave选择,决定MSP430用作I2C中的Master还是Slave。 UCMODEx:模式选择:SPI或者I2C,同时SPI还分为三线和四线模式。 UCSSELx:时钟源选择,建议选SMCLK吧,频率高一点,精度也就高一点。 UCTXACK:回应地址正确,这个是再Slave或者多Master模式下,开启地址掩码功能后,只对比除去掩码的剩下地址,如果一致的话,需要发送个地址确认位(UCSWACK=1时需要手动设置发送,UCSWACK=0时会自动发送),这个就是那个地址确认位。 UCTR:发送还是接受,数据给Slave时是发送,读的时候则是接受或者作为Slave也是接受。 UCTXNACK:发送ACK信号,在Slave模式下使用。 UCTXSTP:生成STOP信号,在Master模式下使用。 UCTXSTT:生成起始信号,在Master模式下使用。 UCSWRST:软件复位使能,默认是1,即不能写一些寄存器设置I2C参数,有些寄存器想进行操作时需要复位这一位。 UCBxCTLW1               UCETXINT:这一位仅在Slave模式下有用,决定着什么时候会置位UCTXIFG0(这一位置位标志着有能力去发送数据了),当这一位是1时,收到Master发送过来的START信号就会置位,当这一位是0时,则等到接收到Master发送的地址与自己的地址匹配时,才会置位UCTXIFG0(注意这种情况下地址1-3都要disable)。               UCCLTO:I2C总线时钟超时,也就是可能总线上卡死了,这一位用来设置这个时间,也可以关闭此项功能。如果设置了时间,在超时之后会触发UCCLTOIFG中断,用户可以在中断里重新初始化I2C。               UCSTPNACK:这一位是指在MCU作为Master接受数据时,在收到Slave的最后一个字节数据后可以发送一个响应给Slave,不过这并不符合I2C协议,因此只用在一些特定场合,正常的I2C协议,请忽略。 UCSWACK:看UCBxCTLW0中的UCTXACK描述,这一位和地址掩码有关系。               UCASTPx:自动生成STOP设置,这一位只用在Master模式下,在设置自动生成STOP信号后,发送完设置长度的数据后,I2C内核直接自动发送停止位,这样会简化用户操作。注意:你可能会遇到一个情况:设置自动STOP后,会设置一个发送数据的长度,而这个数据长度寄存器,也就是UCTBCNTx,这个是8位的,也就是最大值就是255了,因此,如果I2C一次性需要传递的数据包超过了255字节,那么有两种方案解决:不要开启STOP,选择手动设置STOP信号,或者启动DMA模块,这两张方式都可以。手动STOP简单一点,DMA速度快一点。               UCGLITx:错误检测位,这一位可以检测信号线上的毛刺噪声,建议直接默认就好啦。 UCBxBRW                这个寄存器是控制I2C波特率的,目前MSP430的I2C模块支持快速的400Kbps(资料中说的严谨,起始可以更快的)。那么如何计算波特率的呢?看下面框图: 就是对时钟进行分频后,就直接传输给SCL线上了,因此很容易计算,在选择时钟源之后,时钟源的频率除以这一位,就是SCL的时钟频率。 UCBxSTATW UCBCNTx:只读寄存器,用来获取I2C总线上接受或者发送的数据量。 UCSCLLOW:用来查看SCL状态,可以确定是否有其他设备将此总线时钟拉低了。 UCGC:只读寄存器,标志着是否接收到了通用的Call 地址。 UCBBUSY:只读寄存器,用来查看总线上是否繁忙,一般情况下,为了保证数据发送的严谨性,在数据发送前都要查询这一位来决定是否可以发送数据的。   UCBxTBCNT UCTBCNTx:在上面自动生成STOP信号时提过,这一位用来设置I2C一包数据发送的数量。 UCBxRXBUF I2C数据接受缓冲区,在收到I2C接受中断后(当然是在使能中断后啦),接收到的数据会存放在这个缓冲区里,需要读取出来,读取后会自动清除接收中断。   UCBxTXBUF               I2C数据发送缓冲区,也就是如果你想通过I2C协议发送一个数据,那么你只需要把这个数据写入这个寄存器中即可,当数据移入移位寄存器后,开始发送,发送完成后则会触发发中断,代表着当前寄存器的值已经空了,数据已经发送完成,可以写入下一个数据进行发送了。 UCBxI2COA0               I2C的general call是一个什么呢? 就类似于广播模式嘛,地址就是0,更多详细资料,请查看I2C官网:https://www.i2c-bus.org/addressing/(PS:推荐大家有问题多去官网查看,官方发布的肯定没什么问题,理解起来不会有误区)                UCOAEN:使能自己的I2C地址。                I2COAx:自己的I2C地址0。 UCBxI2COA1 参考UCBxI2COA0                UCOAEN:使能自己的I2C地址。                I2COAx:自己的I2C地址1。   UCBxI2COA2 参考UCBxI2COA0                UCOAEN:使能自己的I2C地址。                I2COAx:自己的I2C地址2。   UCBxI2COA3 参考UCBxI2COA0                UCOAEN:使能自己的I2C地址。                I2COAx:自己的I2C地址3。 总的来说,就是MSP430的I2C模块可以设置4个Slave地址,可以产生不同的I2C中断。 UCBxADDRX               ADDRXx:只读寄存器,接收到数据对方的地址。 UCBxADDMASK                ADDMASKx:地址掩码,可以选择性的接受对象固定地址的设备发送来的数据。 UCBxI2CSA               I2CSAx:Slave设备的地址,注意,这个只用在MCU作为Master模式下,这一位用来设置你要发送的Slave设备他的地址。 UCBxIE                各种各样的中断使能位,这个和IFG中断标志位是匹配的,也就是使能相应的中断后,产生中断的情况下后,会置位相应的中断标志位,然后产生中断。具体每个中断时什么用,请看IFG寄存器的描述。 UCBxIFG               中断标志位寄存器,看起来好多吧,最常用的就是UCTXIFG0和UCRXIF0了,当然一些NACK,STT,STP也会用到,具体内容看下面这四张图:分别表示在Slave模式下T/R和Master下T/R,什么时候会将这些标志位置位(7bit地址模式,10bit模式的类似,请直接擦看官方的user guide)   这四张图解释的很清楚,在I2C数据包那一块会触发什么中断,这样用户可以很灵活的使用这些中断标志位和中断入口。 UCBxIV 中断向量表,可以和中断标志位匹配。 好啦,寄存器内容讲解完成后,接下来就是如何使用的环节了,直接上程序吧(MS430FR2355): 其实寄存器很多,但是真正常用的寄存器很少,其他的直接默认就行了,因此不用担心看完了记不住,不重要的,看下下面程序,哪些不懂得地方直接回去找就好啦,User guide就像一个字典,你不需要去背,需要的是在遇到问题是,如何去查找就行。 Master模式+Slave模式:(单个地址,Slave在接收到Master数据后,发送从0开始的递增数据)两个程序可以下载到两个MCU中,实现两个MCU的I2C通信验证。 Maser 程序: #include <msp430.h> volatile unsigned char RXData; int main(void) {     WDTCTL = WDTPW | WDTHOLD;     // Configure GPIO     P1OUT &= ~BIT0;                         // Clear P1.0 output latch     P1DIR |= BIT0;                          // For LED     P1SEL0 |= BIT2 | BIT3;                  // I2C pins     // Disable the GPIO power-on default high-impedance mode to activate     // previously configured port settings     PM5CTL0 &= ~LOCKLPM5;     // Configure USCI_B0 for I2C mode     UCB0CTLW0 |= UCSWRST;                   // Software reset enabled     UCB0CTLW0 |= UCMODE_3 | UCMST | UCSYNC; // I2C mode, Master mode, sync     UCB0CTLW1 |= UCASTP_2;                  // Automatic stop generated                                             // after UCB0TBCNT is reached     UCB0BRW = 0x0008;                       // baudrate = SMCLK / 8     UCB0TBCNT = 0x0005;                     // number of bytes to be received     UCB0I2CSA = 0x0048;                     // Slave address     UCB0CTL1 &= ~UCSWRST;     UCB0IE |= UCRXIE | UCNACKIE | UCBCNTIE;     while (1)     {         __delay_cycles(2000);         while (UCB0CTL1 & UCTXSTP);         // Ensure stop condition got sent         UCB0CTL1 |= UCTXSTT;                // I2C start condition         __bis_SR_register(LPM0_bits|GIE);   // Enter LPM0 w/ interrupt     } } #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCI_B0_VECTOR __interrupt void USCIB0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCIB0_ISR (void) #else #error Compiler not supported! #endif {   switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))   {     case USCI_NONE: break;                  // Vector 0: No interrupts     case USCI_I2C_UCALIFG: break;           // Vector 2: ALIFG     case USCI_I2C_UCNACKIFG:                // Vector 4: NACKIFG       UCB0CTL1 |= UCTXSTT;                  // I2C start condition       break;     case USCI_I2C_UCSTTIFG: break;          // Vector 6: STTIFG     case USCI_I2C_UCSTPIFG: break;          // Vector 8: STPIFG     case USCI_I2C_UCRXIFG3: break;          // Vector 10: RXIFG3     case USCI_I2C_UCTXIFG3: break;          // Vector 14: TXIFG3     case USCI_I2C_UCRXIFG2: break;          // Vector 16: RXIFG2     case USCI_I2C_UCTXIFG2: break;          // Vector 18: TXIFG2     case USCI_I2C_UCRXIFG1: break;          // Vector 20: RXIFG1     case USCI_I2C_UCTXIFG1: break;          // Vector 22: TXIFG1     case USCI_I2C_UCRXIFG0:                 // Vector 24: RXIFG0       RXData = UCB0RXBUF;                   // Get RX data       __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0       break;     case USCI_I2C_UCTXIFG0: break;          // Vector 26: TXIFG0     case USCI_I2C_UCBCNTIFG:                // Vector 28: BCNTIFG       P1OUT ^= BIT0;                        // Toggle LED on P1.0       break;     case USCI_I2C_UCCLTOIFG: break;         // Vector 30: clock low timeout     case USCI_I2C_UCBIT9IFG: break;         // Vector 32: 9th bit     default: break;   } } Slave程序: #include <msp430.h> volatile unsigned char TXData; int main(void) {   WDTCTL = WDTPW | WDTHOLD;   // Configure GPIO   P1SEL0 |= BIT2 | BIT3;                    // I2C pins   // Disable the GPIO power-on default high-impedance mode to activate   // previously configured port settings   PM5CTL0 &= ~LOCKLPM5;   // Configure USCI_B0 for I2C mode   UCB0CTLW0 = UCSWRST;                      // Software reset enabled   UCB0CTLW0 |= UCMODE_3 | UCSYNC;           // I2C mode, sync mode   UCB0I2COA0 = 0x48 | UCOAEN;               // own address is 0x48 + enable   UCB0CTLW0 &= ~UCSWRST;                    // clear reset register   UCB0IE |= UCTXIE0 | UCSTPIE;              // transmit,stop interrupt enable     __bis_SR_register(LPM0_bits | GIE);     // Enter LPM0 w/ interrupts     __no_operation(); } #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCI_B0_VECTOR __interrupt void USCIB0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCIB0_ISR (void) #else #error Compiler not supported! #endif {   switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))   {     case USCI_NONE: break;                  // Vector 0: No interrupts     case USCI_I2C_UCALIFG: break;           // Vector 2: ALIFG     case USCI_I2C_UCNACKIFG: break;         // Vector 4: NACKIFG     case USCI_I2C_UCSTTIFG: break;          // Vector 6: STTIFG     case USCI_I2C_UCSTPIFG:                 // Vector 8: STPIFG       TXData = 0;       UCB0IFG &= ~UCSTPIFG;                 // Clear stop condition int flag       break;     case USCI_I2C_UCRXIFG3: break;          // Vector 10: RXIFG3     case USCI_I2C_UCTXIFG3: break;          // Vector 14: TXIFG3     case USCI_I2C_UCRXIFG2: break;          // Vector 16: RXIFG2     case USCI_I2C_UCTXIFG2: break;          // Vector 18: TXIFG2     case USCI_I2C_UCRXIFG1: break;          // Vector 20: RXIFG1     case USCI_I2C_UCTXIFG1: break;          // Vector 22: TXIFG1     case USCI_I2C_UCRXIFG0: break;          // Vector 24: RXIFG0     case USCI_I2C_UCTXIFG0:        UCB0TXBUF = TXData++;        break;                               // Vector 26: TXIFG0     case USCI_I2C_UCBCNTIFG: break;         // Vector 28: BCNTIFG     case USCI_I2C_UCCLTOIFG: break;         // Vector 30: clock low timeout     case USCI_I2C_UCBIT9IFG: break;         // Vector 32: 9th bit     default: break;   } } Master模式+Slave模式:(单个地址,Slave在接收到Master数据后,接收到的数据)两个程序可以下载到两个MCU中,实现两个MCU的I2C通信验证。这个程序里一个Slave可以设置四个地址,产生四个中断,这个也是MSP430 I2C模块的特点。 Maser 程序: #include <msp430.h> unsigned char TXData[]= {0xA1,0xB1,0xC1,0xD1};        // Pointer to TX data unsigned char SlaveAddress[]= {0x0A,0x0B,0x0C,0x0D}; unsigned char TXByteCtr; unsigned char SlaveFlag = 0; int main(void) {     WDTCTL = WDTPW | WDTHOLD;                         // Stop watchdog timer     // Configure Pins for I2C     P1SEL0 |= BIT2 | BIT3;                            // I2C pins     // Disable the GPIO power-on default high-impedance mode     // to activate previously configured port settings     PM5CTL0 &= ~LOCKLPM5;     // Configure USCI_B0 for I2C mode     UCB0CTLW0 |= UCSWRST;                             // put eUSCI_B in reset state     UCB0CTLW0 |= UCMODE_3 | UCMST;                    // I2C master mode, SMCLK     UCB0BRW = 0x8;                                    // baudrate = SMCLK / 8     UCB0CTLW0 &=~ UCSWRST;                            // clear reset register     UCB0IE |= UCTXIE0 | UCNACKIE;                     // transmit and NACK interrupt enable     SlaveFlag =0;     while(1)     {     __delay_cycles(1000);                             // Delay between transmissions     UCB0I2CSA = SlaveAddress[SlaveFlag];              // configure slave address     TXByteCtr = 1;                                    // Load TX byte counter     while (UCB0CTLW0 & UCTXSTP);                      // Ensure stop condition got sent     UCB0CTLW0 |= UCTR | UCTXSTT;                      // I2C TX, start condition     __bis_SR_register(LPM0_bits | GIE);               // Enter LPM0 w/ interrupts                                                       // Remain in LPM0 until all data                                                       // is TX'd     // Change Slave address     SlaveFlag++;     if (SlaveFlag>3)                                  // Roll over slave address       {         SlaveFlag =0;       }     } } #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCI_B0_VECTOR __interrupt void USCIB0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCIB0_ISR (void) #else #error Compiler not supported! #endif {   switch(__even_in_range(UCB0IV,USCI_I2C_UCBIT9IFG))   {         case USCI_NONE: break;                        // Vector 0: No interrupts break;         case USCI_I2C_UCALIFG: break;         case USCI_I2C_UCNACKIFG:             UCB0CTL1 |= UCTXSTT;                      //resend start if NACK           break;                                      // Vector 4: NACKIFG break;         case USCI_I2C_UCSTTIFG: break;                // Vector 6: STTIFG break;         case USCI_I2C_UCSTPIFG: break;                // Vector 8: STPIFG break;         case USCI_I2C_UCRXIFG3: break;                // Vector 10: RXIFG3 break;         case USCI_I2C_UCTXIFG3: break;                // Vector 14: TXIFG3 break;         case USCI_I2C_UCRXIFG2: break;                // Vector 16: RXIFG2 break;         case USCI_I2C_UCTXIFG2: break;                // Vector 18: TXIFG2 break;         case USCI_I2C_UCRXIFG1: break;                // Vector 20: RXIFG1 break;         case USCI_I2C_UCTXIFG1: break;                // Vector 22: TXIFG1 break;         case USCI_I2C_UCRXIFG0: break;                // Vector 24: RXIFG0 break;         case USCI_I2C_UCTXIFG0:         if (TXByteCtr)                                // Check TX byte counter            {             UCB0TXBUF = TXData[SlaveFlag];            // Load TX buffer             TXByteCtr--;                              // Decrement TX byte counter            }         else            {             UCB0CTLW0 |= UCTXSTP;                     // I2C stop condition             UCB0IFG &= ~UCTXIFG;                      // Clear USCI_B0 TX int flag             __bic_SR_register_on_exit(LPM0_bits);     // Exit LPM0            }           break;                                      // Vector 26: TXIFG0 break;         case USCI_I2C_UCBCNTIFG: break;               // Vector 28: BCNTIFG         case USCI_I2C_UCCLTOIFG: break;               // Vector 30: clock low timeout         case USCI_I2C_UCBIT9IFG: break;               // Vector 32: 9th bit         default: break;   } } Slave程序: #include <msp430.h> unsigned char RXData0=0; unsigned char RXData1=0; unsigned char RXData2=0; unsigned char RXData3=0; int main(void) {     WDTCTL = WDTPW | WDTHOLD;                             // Stop watchdog timer     // Configure Pins for I2C     P1SEL0 |= BIT2 | BIT3;                                // I2C pins     // Disable the GPIO power-on default high-impedance mode     // to activate previously configured port settings     PM5CTL0 &= ~LOCKLPM5;     // Configure USCI_B0 for I2C mode     UCB0CTLW0 |= UCSWRST;                                 //Software reset enabled     UCB0CTLW0 |= UCMODE_3;                                //I2C slave mode, SMCLK     UCB0I2COA0 = 0x0A | UCOAEN;                           //SLAVE0 own address is 0x0A| enable     UCB0I2COA1 = 0x0B | UCOAEN;                           //SLAVE1 own address is 0x0B| enable     UCB0I2COA2 = 0x0C | UCOAEN;                           //SLAVE2 own address is 0x0C| enable     UCB0I2COA3 = 0x0D | UCOAEN;                           //SLAVE3 own address is 0x0D| enable     UCB0CTLW0 &=~UCSWRST;                                 //clear reset register     UCB0IE |=  UCRXIE0 | UCRXIE1| UCRXIE2 | UCRXIE3;      //receive interrupt enable     __bis_SR_register(LPM0_bits | GIE);                   // Enter LPM0 w/ interrupts     __no_operation(); } #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCI_B0_VECTOR __interrupt void USCIB0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCIB0_ISR (void) #else #error Compiler not supported! #endif {    switch(__even_in_range(UCB0IV,USCI_I2C_UCBIT9IFG))     {       case USCI_NONE: break;                            // Vector 0: No interrupts break;       case USCI_I2C_UCALIFG: break;                     // Vector 2: ALIFG break;       case USCI_I2C_UCNACKIFG: break;                   // Vector 4: NACKIFG break;       case USCI_I2C_UCSTTIFG: break;                    // Vector 6: STTIFG break;       case USCI_I2C_UCSTPIFG: break;                    // Vector 8: STPIFG break;       case USCI_I2C_UCRXIFG3:                           // SLAVE3         RXData3 = UCB0RXBUF;         break;                                          // Vector 10: RXIFG3 break;       case USCI_I2C_UCTXIFG3: break;                    // Vector 14: TXIFG3 break;       case USCI_I2C_UCRXIFG2:                           // SLAVE2         RXData2 = UCB0RXBUF;         break;                                          // Vector 16: RXIFG2 break;       case USCI_I2C_UCTXIFG2: break;                    // Vector 18: TXIFG2 break;       case USCI_I2C_UCRXIFG1:                           // SLAVE1         RXData1 = UCB0RXBUF;         break;                                          // Vector 20: RXIFG1 break;       case USCI_I2C_UCTXIFG1: break;                    // Vector 22: TXIFG1 break;       case USCI_I2C_UCRXIFG0:                           // SLAVE0         RXData0 = UCB0RXBUF;                            // Get RX data         break;                                          // Vector 24: RXIFG0 break;       case USCI_I2C_UCTXIFG0: break;                    // Vector 26: TXIFG0 break;       case USCI_I2C_UCBCNTIFG: break;                   // Vector 28: BCNTIFG break;       case USCI_I2C_UCCLTOIFG: break;                   // Vector 30: clock low timeout break;       case USCI_I2C_UCBIT9IFG: break;                   // Vector 32: 9th bit break;       default: break;     } } 最后,I2C通信仅仅是规定了协议格式 START STOP等,其实在和外设通信过程中,会在I2C基础上叠加一个特殊的东西,比如你去读EEPROM,那么I2C的数据段需要包括你想读的EEPROM地址,等数据,这个要看每个使用I2C协议的芯片的规定。 最后最后,如果你不想捣鼓这些I2C的东西,你就喜欢UART,那么看下面这个Application Note: Uart to I2c:   http://www.ti.com/lit/an/slaa908/slaa908.pdf  

最近访客

< 1/1 >

统计信息

已有14人来访过

  • 芯币:72
  • 好友:2
  • 主题:13
  • 回复:6
  • 课时:--
  • 资源:--

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言