liminary1138学习手记
更新时间:2024-04-18 18:09:01 阅读量: 综合文库 文档下载
- liminary推荐度:
- 相关推荐
关于文件........................................................................................................................................... 2 1、Bit-band位操作 .......................................................................................................................... 2 2、中断............................................................................................................................................. 3
抢占优先级 ............................................................................................................................... 3 3、系统控制 ..................................................................................................................................... 5 4、定时器......................................................................................................................................... 5 5、模拟比较器COMP .................................................................................................................... 6 6、模数转换ADC ........................................................................................................................... 6 7、滴答定时器 ................................................................................................................................. 6 8、接口部分 ..................................................................................................................................... 7
(1)UART .............................................................................................................................. 7 (2)SSI ................................................................................................................................... 9 (3)I2C ................................................................................................................................. 10
经过这几天的学习,对比之前几天的stm32的学习(由于暂时缺少板子,临时改变,stm32看了大概两周,而esayarm1138已经五天有余),感觉要容易很多。可能是由于函数库的原因吧。
对于32位的编程,一个整体的框架就是:首先是对相关外围模块的使能或者说是时钟的使能,紧接着就是相关端口模块的使能与端口的配置作业,用得到中断的地方要开中断,当然要全部开放的,少一个中断就无法进行,再就是模块的使能了。对于中端处理函数来说,首先是得注册的,这样才能对相关的中端进行处理。具体的中端操作是,读状态,清中断,然后才是相关的处理。
要实现一个功能,就得用得其中的模块,所以首先我们要做的事是能该模块,可以由函数SysCtlPeripheralEnable(xxxx)实现;当然不也得用带芯片的某些或者某个管脚,这就要求我们来使能管脚所在的端口(GPIOx),仍然可以由函数SysCtlPeripheralEnable(xxxx)实现,对于stm32来讲似乎是时钟使能吧?再然后就是管脚的配置了,像输入输出,上拉下拉,uart,i2c等等吧,都有具体的函数(GPIOPinTypexxxx())来实现,当然,对于有些模块来说最后我们还得使能该模块的端口(如UART)。
关于文件
hw_memmap.h -- 宏定义memory map
hw_xx.h --宏定义某个片内或者外围设备的寄存器地址其中包含了某
个寄存器位
xx.h -- 声明函数 xx.c -- 定义函数
1、Bit-band位操作
#define HWREGB(x) (*((volatile unsigned char *)(x)))
对存储单元或寄存器当中某一位的访问,按照传统的“读-改-写”分三步走的操作模式,效率不高;而采用“bit-band”后成为“直接读”和“直接写”,效率明显提高。在整个4GB存储空间里划分出了2个位操作区域,可以分别支持对片内SRAM和片内外设的位操作。
Stellaris器件内部的SRAM的地址是0x2000.0000,为了减少读-修改-写(RMW) 操作的时间,ARM在Cortex-M3处理器中引入了bit-banding技术。在bit-banding使能的处理器中,存储器映射的特定区域(SRAM和外设空间)能够使用地址别名,在单个原子操作中访问各个位。只改变其中的一位。
使用下面的公式来计算bit-band别名:
bit-band别名 = bit-band基址 + (字节偏移量 * 32) + (位编号 * 4)??这里就说明了在
宏定义中左移5位与左移2位的情况了
如果要修改地址0x2000.1000的位3,则bit-band别名计算如下: 0x2200.0000 + (0x1000 * 32) + (3 * 4) = 0x2202.000C 也就是((0x22001000)&(0xF0000000))|(0x02000000)|(((0x000FFFFF)&(0x22001000))<<5)|((0xb)<<2)
2、中断
具体的操作步骤如下:
1、某个模块的使能,进行必要的基本配置 2、配置中断类型
3、调用片内外设具体中断的使能函数
调用函数IntEnable( ),使能片内外设的总中断 调用函数IntMasterEnable( ),使能处理器总中断 4、编写具体的中断服务函数:读状态GPIOPinIntStatus( )、清状态GPIOPinIntClear( ),判断、操作
5、注册中断处理函数,一是直接利用中断注册函数,另一种方法需要修改启动文件 修改启动文件的方法如下:
Keil 在Keil开发环境下,启动文件“Startup.s”是用汇编写的,以中断服务函数“void I2C_ISR(void)”为例,找到“Vectors”表格,在其前面插入声明 EXTERN I2C_ISR
再根据“Vectors”表格的注释内容找到外设I2C0的位置,把相应的“IntDefaultHandler”替换为“I2C_ISR”,完成。
IAR 在IAR开发环境下,启动文件“startup_ewarm.c”是用C语言写的,很好理解。仍以中断服务函数“void I2C_ISR(void)”为例,先在向量表的前面插入函数声明: void I2C_ISR(void);
然后在向量表里,根据注释内容找到外设I2C0的位置,把相应的“IntDefaultHandler”替换为“I2C_ISR”,完成。
抢占优先级
由函数IntPriorityGroupingSet( )设置中断控制器的优先级分组
Cortex-M3用8位来设置优先级,但在stm32中仅用4位来设置优先级。 对于同一抢占优先级的中断来说,即便是优先级高的也不能中断正在执行的中断,只有高抢占优先级的中断方可中断正在执行中的中断。应该是这么理解的。还有一些疑问,有待进一步解决。
下边的五行我个人认为是stm32的关于嵌套中断的说法:
0位抢占优先级,4位子优先级:设置为16级子优先级,不使用抢占式优先级; 1位抢占优先级,3位子优先级:设置为8级子优先级,2级抢占式优先级;
2位抢占优先级,2位子优先级:设置为4级子优先级,4级抢占式优先级; 3位抢占优先级,1位子优先级:设置为2级子优先级,8级抢占式优先级; 4位抢占优先级,0位子优先级:设置为不使用子优先级,16级抢占式优先级;
再回到luminary1138,,举例说明一下这个问题:KEY1的中断优先级高于KEY2的,如果函数IntPriorityGroupingSet( )参数是0或1,则KEY1和KEY2中断都不能互相抢占对方;如果参数是2,则KEY1中断的抢占式优先级为0、KEY2中断的抢占式优先级是1,因此KEY1中断就可以抢占KEY2中断;如果参数是3~7,则相当于默认的8级中断嵌套。我个人认为这是luminary的特殊规定,因为它只有八个优先级,当其为0、1是,为同一抢占优先级,故而不可抢占,当期大于等于2时,他们处于不同的抢占优先级,因此能都抢占。至于抢占优先级是怎么分的,还不清楚。
在STM32/Cortex-M3中是通过改变CPU的当前优先级来允许或禁止中断。
PRIMASK位:只允许NMI和hard fault异常,其他中断/异常都被屏蔽(当前CPU优先级=0)。 AULTMASK位:只允许NMI,其他所有中断/异常都被屏蔽(当前CPU优先级=-1)。 在STM32固件库中(stm32f10x_nvic.c和stm32f10x_nvic.h) 定义了四个函数操作PRIMASK位和FAULTMASK位,改变CPU的当前优先级,从而达到控制所有中断的目的。 下面两个函数等效于关闭总中断: void NVIC_SETPRIMASK(void); void NVIC_SETFAULTMASK(void); 下面两个函数等效于开放总中断: void NVIC_RESETPRIMASK(void); void NVIC_RESETFAULTMASK(void); 上面两组函数要成对使用,但不能交叉使用。 例如: 第一种方法:
NVIC_SETPRIMASK(); //关闭总中断 NVIC_RESETPRIMASK();//开放总中断 第二种方法:
NVIC_SETFAULTMASK(); //关闭总中断 NVIC_RESETFAULTMASK();//开放总中断 常常使用:
NVIC_SETPRIMASK(); // Disable Interrupts NVIC_RESETPRIMASK(); // Enable Interrupts
3、系统控制
主要有以下方面: LDO 时钟控制 PLL 振荡器 PWM ADC 复位控制 外设控制
睡眠与深度睡眠:可以让某些端口在这种情况下使能,产生中断,使系统唤醒。 对于系统的控制
4、定时器
有以下功能:
32位单次触发定时 32位周期定时 32位RTC定时 16位周期定时 16位单次触发定时 16位输入边沿计数捕获 16位输入边沿定时捕获 16位PWM
每一个Timer模块对应两个CCP管脚。CCP是“Capture Compare PWM”的缩写,意为“捕获/比较/脉宽调制”。在32位单次触发和周期定时模式下,CCP功能无效(与之复用的GPIO管脚功能仍然正常)。在32位RTC模式下,偶数CCP管脚(CCP0、CCP2、CCP4等)作为RTC时钟源的输入,而奇数CCP管脚(CCP1、CCP3、CCP5等)无效。在16位模式下,计数捕获、定时捕获、PWM功能都会用到CCP管脚,对应关系是:Timer0A对应CCP0、Timer0B对应CCP1,Timer1A对应CCP2、Timer1B对应CCP3,Timer2A对应CCP4,Timer2B对应CCP5,Timer3A对应CCP6,Timer3B对应CCP7,依此类推。
对于16位输入边沿定时捕获,
在该模式中,TimerA或TimerB被配置为自由运行的16位递减计数器,允许在输入信号的上升沿或下降沿捕获事件。该模式的工作过程是:设置装载值(默认为0xFFFF)、捕获边沿类型;计数器被使能后开始自由运行,从装载值开始递减计数,计数到0时重装初值,继续计数;如果从CCP管脚上出现有效的输入脉冲边沿事件,则当前计数值被自动复制到一个特定的寄存器里,该值会一直保存不变,直至遇到下一个有效输入边沿时被刷新。为了能够
及时读取捕获到的计数值,应当使能边沿事件捕获中断,并在中断服务函数里读取。 定时器的初始化使用:
使能Timer模块、配置、使能内部触发脉冲的产生、调试时暂停计数(必要的)、设置Timer初值、使能Timer计数。
5、模拟比较器COMP
对于管脚的配置应该是数字的,开漏或者是推挽的,不可以用GPIOPinTypeComp()来进行设置。在luminary中用函数CompOut()来设置。 模拟比较器的初始化使用:
使能COMP模块、使能反相输入端所在的GPIO、配置相关管脚位COMP功能、(使能同相输入端所在的GPIO、配置相关管脚为COMP功能)或者是(配置内部参考电压)、模拟比较器的配置,当然有中断的话还得使能COMP中断、使能COMP模块中断、使能Master中断。
6、模数转换ADC
Luminary1138包含10个ADC模块,8通道输入,具可编程的序列发生器,可在不受处理器干涉的情况下采样。 对ADC的初始化包括:
使能ADC模块、设置其采样速率、配置前禁止采样序列、采样序列的配置(编号、触发事件、优先级)、使能ADC采样序列中断、使能处理器中断、使能采样序列。 对ADC的采样:
触发采样序列、等待采样结束、清除采样结束标志、读取ADC转换结果(其中采样结束标志是自定义的全局变量)。
7、滴答定时器
初值的设置、允许中断
8、接口部分
(1)UART
波特率除数:BRD= BRDI.BRDF = SystemClock/(16×BaudRate)
中断控制
出现以下情况时,可使UART产生中断:
??FIFO溢出错误 ??线中止错误(line-break,即Rx信号一直为0的状态,包括校验位和停止位在内) ??奇偶校验错误 ??帧错误(停止位不为1) ??接收超时(接收FIFO已有数据但未满,而后续数据长时间不来) ??发送 ??接收
BRD = BRDI + BRDF = SysClk / (16 * 波特率)
以下等式是6位小数 (被加载到UARTFBRD寄存器中的 DIVFRAC 位域) 的计算方法,即——波特率
除数的小数部分乘以64,然后为了消除四舍五入误差再加上0.5。 UARTFBRD[DIVFRAC] = integer(BRDF * 64 + 0.5)
UART产生一个16倍于波特率的内部波特率参考时钟(称作Baud16)。这个参考时钟经过16分频后
便可产生发送时钟,它还可以在接收操作过程中用作错误检测。
UARTIBRD和 UARTFBRD 寄存器连同UART线控,高字节 (UARTLCRH) 寄存器 (见 293页)一起共
同组成一个内部30位寄存器。这个内部寄存器仅在对UARTLCRH进行写操作时才会更新,所以为了
使修改波特率除数生效,后面必须紧跟一个写UARTLCRH寄存器操作。
由于所有中断事件在发送到中断控制器之前会一起进行或运算操作,所以任意时刻UART只能向中断产生一个中断请求。通过查询中断状态函数UARTIntStatus( ),软件可以在同一个中断服务函数里处理多个中断事件(多个并列的if语句)。
发送时,数据被写入发送FIFO,发送时,数据被写入发送FIFO,BUSY位仅在发送FIFO为空,且已从移位寄存器发送最后一个字符,包括停止位时才变无效在UART接收器空闲时,如果数据输入变成“低电平”,即接收到了起始位,则接收计数器开始运行,并且数据在Baud16的第8个周期被采样。如果Rx在Baud16的第8周期仍然为低电平,则起始位有效,否则会被认为是错误的起始位并将其忽略。
如果起始位有效,则根据数据字符被编程的长度,在Baud16的每第16个周期对连续的数据位(即一个位周期之后)进行采样。如果奇偶校验模式使能,则还会检测奇偶校验位。 最后,如果Rx为高电平,则有效的停止位被确认,否则发生帧错误。当接收到一个完整的字符时,将数据存放在接收FIFO中。
发送FIFO的基本工作过程:只要有数据填充到发送FIFO里,就会立即启动发送过程。
由于发送本身是个相对缓慢的过程,因此在发送的同时其它待发送的数据还可以继续填充到发送FIFO里。当发送FIFO被填满时就不能再继续填充了,否则会造成数据丢失,此时只能等待。这个等待并不会很久,以9600的波特率为例,等待出现一个空位的时间在1ms上下。发送FIFO会按照填入数据的先后顺序把数据一个个发送出去,直到发送FIFO全空时为止。已发送出去的数据会被自动清除,在发送FIFO里同时会多出一个空位。
接收FIFO的基本工作过程:当硬件逻辑接收到数据时,就会往接收FIFO里填充接收到的数据。程序应当及时取走这些数据,数据被取走也是在接收FIFO里被自动删除的过程,因此在接收FIFO里同时会多出一个空位。如果在接收FIFO里的数据未被及时取走而造成接收FIFO已满,则以后再接收到数据时因无空位可以填充而造成数据丢失。
收发FIFO主要是为了解决UART收发中断过于频繁而导致CPU效率不高的问题而引入的。在进行UART通信时,中断方式比轮询方式要简便且效率高。但是,如果没有收发FIFO,则每收发一个数据都要中断处理一次,效率仍然不够高。如果有了收发FIFO,则可以在连续收发若干个数据(可多至14个)后才产生一次中断然后一并处理,这就大大提高了收发效率。
发送FIFO中断处理过程:触发FIFO中断的条件是当发送FIFO里剩余的数据减少到预设的深度时触发中断,发送FIFO中断触发深度级别越浅越好,在中断服务函数里,继续填充发送数据,填满时退出。下次中断时继续填充,直到所有待发送数据都填充完毕为止(可以设置一个软标志来通知主程序)。
接收FIFO中断处理过程:触发FIFO中断的条件是当接收FIFO里累积的数据增加到预设的深度时触发中断,,在使能接收中断的同时一般都还要使能接收超时中断。如果没有接收超时功能,则在接收FIFO未填充到预设深度而对方已经发送完毕的情况下并不会触发中断,结果造成最后接收的有效数据得不到处理的问题。另一种情况是对方发送过程中出现间隔,也不会触发中断,已在接收FIFO里的数据同样得不到及时处理。如果使能了接收超时中断,则在对方发送过程中出现3个数据的传输时间间隔时内就会触发超时中断,从而确保数据能够得到及时的处理。
UART可以进入一个内部回环(Loopback)模式,用于诊断或调试。在回环模式下,从Tx上发送的数据将被Rx输入端接收。
函数UARTCharPut( )以轮询的方式发送数据,如果发送FIFO有空位则填充要发送的数据,如果没有空位则一直等待。
函数UARTCharGet( )以轮询的方式接收数据,如果接收FIFO里有数据则读出数据并返回,如果没有数据则一直等待。
不管是函数UARTCharPut( )还是UARTCharPutNonBlocking( ),在发送数据时实际上都是把数据往发送FIFO一丢然后就退出,而并非在UnTx管脚意义上的真正发送完毕。函数UARTBusy( )是判断UART发送操作是否忙,可用来判定在发送FIFO里的数据是否真正发
送完毕,这包括最后一个数据的最后停止位。在UART转半双工的RS-485通信里,需要在发送完一批数据后将传输方向切换为接收,如果此时发送FIFO里还有数据未被真正发送出去,则过早的方向切换会破坏发送过程。因此运用函数UARTBusy( )进行判定是必要的。
线中止是指UART的接收信号UnRx一直为0的状态(包括校验位和停止位在内)。调用该函数,则会在UnTx管脚输出一个连续的0电平状态,使对方的Rx产生一个线中止条件,并可以触发中断。线中止是个特殊的状态,在某些情况下有特别的用途,例如可以利用它来激活串口ISP下载服务程序、智能化自动握手通信等。
(2)SSI
对于Freescale SPI、MICROWIRE、Texas Instruments3种帧格式,当SSI空闲时串行时钟(SSICLK)都保持不活动状态,只有当数据发送或接收时处于活动状态,SSICLK才在设置好的频率下工作。利用SSICLK的空闲状态可提供接收超时指示。如果一个超时周期之后接收FIFO仍含有数据,则产生超时指示。
对于Freescale SPI和MICROWIRE这两种帧格式,串行帧(SSIFss)管脚为低电平有效,并在整个帧的传输过程中保持有效(被下拉)。
而对于Texas Instruments同步串行帧格式,在发送每帧之前,每遇到SSICLK的上升沿开始的串行时钟周期时,SSIFss管脚就跳动一次。在这种帧格式中,SSI和片外从器件在SSICLK的上升沿驱动各自的输出数据,并在下降沿锁存来自另一个器件的数据。
Freescale SPI格式的主要特性为:SSICLK信号的不活动状态和相位可以通过SSISCR0控制寄存器中的SPO和SPH位来设置。可由SPO来控制不活动时时钟极性,为0时,SSICLK输出稳定的低电平;SPH相位控制位选择捕获数据以及允许数据改变状态的时钟边沿。通过在第一个数据捕获边沿之前允许或不允许时钟转换,从而在第一个被传输的位上产生极大的影响。当SPH相位控制位为0时,在第一个时钟边沿转换时捕获数据。如果SPH位为1,则在第二个时钟边沿转换时捕获数据。
共有四种传输模式。
SSI对从外设器件接收到的数据执行串行到并行转换。CPU可以访问SSI数据寄存器来发送和获得数据。发送和接收路径利用内部FIFO存储单元进行缓冲,以允许最多8个16位的值在发送和接收模式中独立地存储。
SSI包含一个可编程的位速率时钟分频器和预分频器来生成串行输出时钟。尽管最大位速率由外设器件决定,但1.5MHz及更高的位速率仍是支持的。
串行位速率是通过对输入的系统时钟进行分频来获得。虽然理论上SSICLK发送时钟可达到25MHz,但模块可能不能在该速率下工作。发送操作时,系统时钟速率至少必须时SSICLK的两倍。接收操作时,系统时钟速率指导必须时SSICLK的12倍。
对FIFO的访问是通过SSI数据寄存器(SSIDR)中写入与读出数据来实现的,SSIDR为16为宽的数据寄存器,可以对它进行读写操作,SSIDR实际对应两个不同的物理地址,以分别完成对发送FIFO和接收FIFO的操作。
发送FIFO
通用发送FIFO是16位宽、8单元深、先进先出的存储缓冲区。CPU通过写SSI数据寄存器SSIDR来将数据写入发送FIFO,数据在由发送逻辑读出之前一直保存在发送FIFO中。
当SSI配置为主机或从机时,并行数据先写入发送FIFO,再转换成串行数据并通过SSITx管脚分别发送到相关的从机或主机。 接收FIFO
通用接收FIFO是一个16位宽、8单元深、先进先出的存储缓冲区。从串行接口接收到的数据在由CPU读出之前一直保存在缓冲区中,CPU通过读SSIDR寄存器来访问读FIFO。
当SSI配置位主机或从机时,通过SSIRx管脚接收到的串行数据转换成并行数据后装载到相关的从机或主机接收FIFO。 SSI在满足以下条件时能够产生中断: ??发送FIFO服务
??接收FIFO服务 ??接收FIFO超时 ??接收FIFO溢出
(3)I2C
SCL 时钟速率
I2C总线时钟速率由以下参数决定: ??CLK_PRD:系统时钟周期 ??SCL_LP:SCL低电平时间(固定为6) ??SCL_HP:SCL高电平时间(固定为4) ??TIMER_PRD:位于寄存器I2CMTPR(I2C Master Timer Period)里的可编程值 I2C时钟周期的计算方法如下:
SCL_PERIOD = 2 ×(1 + TIMER_PRD)×(SCL_LP + SCL_HP)× CLK_PRD
中断控制
I2C总线能够在观测到以下条件时产生中断: ??主机传输完成 ??主机传输过程中出现错误 ??从机传输时接收到数据
?从机传输时收到主机的请求
对I2C主机模块和从机模块来说,这是独立的中断信号。但两个模块都能产生多个中断时,仅有单个中断信号被送到中断控制器。 主机中断
当传输结束(发送或接收)、或在传输过程中出现错误时,I2C主机模块产生一个中断。如果最后一次传输没有被从机应答或如果主机由于与另一个主机竞争时丢失仲裁而被强制放弃总线的所有权,那么会发出一个错误条件。如果没有检测到错误,则应用可继续执行传输。如果应用不要求使用中断(即基于轮询的设计方法),那么原始中断状态总是可以通过函数调用I2CMasterIntStatus(false)来观察到。 从机模块在它接收到来自I2C主机的请求时产生中断 从机中断 从机模块在它接收到来自I2C主机的请求时产生中断。 I2C模块在主机模式下有多种收发模式:
??主机单次发送:S | SLA+W | data | P ??主机单次接收:S | SLA+R | data | P ??主机突发发送:S | SLA+W | data | ? | P ??主机突发接收:S | SLA+R | data | ? | P ??主机突发发送后主机接收:S | SLA+W | data | ? | Sr | SLA+R | ? | P ??主机突发接收后主机发送:S | SLA+R | data | ? | Sr | SLA+W | ? | P
在传输格式里,S为起始条件、P为停止条件、SLA+W为从机地址加写操作、SLA+R为从机地址加读操作、data为传输的有效数据、Sr为重复起始条件(在物理波形上等同与S)。在单次模式中每次仅能传输一个字节的有效数据,而在突发模式中一次
可以传输多个字节的有效数据。在实际应用当中以“主机突发发送”和“主机突发发送后主机接收”这两种模式最为常见。
当I2C模块作为总线上的从机时,收发操作仍然是由(另外的)主机控制的。当从机被寻址到时会触发中断,将被要求接收或发送数据。通过调用函数I2CSlaveStatus( ),就能获得主机的操作要求,有以下几种情况: ??主机已经发送了第1个字节:该字节应当被视为数据地址(或数据地址首字节) ??主机已经发送了数据:应当及时读取该数据(也可能是数据地址后继字节) ??主机要求接收数据:应当根据数据地址找到存储的数据然后回送给主机
###############################################################################
主机对于数据的发送和接受的实现,包含在LM3S_I2CM.h头文件中的接受与发送函数unsigned long I2CM_SendRecv(tI2CM_DEVICE *pDevice, tBoolean bFlag)和中断处理函数void I2C_ISR(void),其思想如下:
###############################################################################
数据地址长度或收发数据大小不能为0,否则不执行任何操作 数据地址长度不能超过4B
将数据地址分解成数组,高位放在gcAddr[0]中 如果是多主机通信,则需要首先等待总线空闲 设置从机地址,写操作 开始发送数据地址
设置状态:发送数据地址 命令:主机突发发送起始
之后发生中断,进入中断处理函数 {
若遇到错误,返回,状态是STAT_IDLE CASE STAT_ADDR:
若数据地址未发送完毕,继续发送数据地址,
命令:主机突发发送继续。这里从机又接收到数据、故而有发生中断, 若数据地址发送完毕,那么,状态改为STAT_DATA(收发数据), 如果为接收数据,设置从机地址,读操作,
只为一个字节的数据大小时,状态改为STAT_FINISH(收发结束), 命令:主机单次接收;
不是一个字节的数据大小时, 命令:主机突发接收起始; 等待总线操作完毕
总线上有数据时触发中断 进入STAT_DATA: // 若是接收操作 读取接收到的数据 / 若数据未接收完毕 命令:主机突发接收继续 /如果数据接收完毕 设置状态:接收完成 命令:主机突发接收完成
//若是发送数据 发送数据
/ 若数据未发送完毕 命令:主机突发发送继 / 若数据发送完毕 设置状态:发送完成 命令:主机突发发送完成 进入STAT_FINISH: // 若是接收操作
// 读取接最后收到的数据 // 设置状态:空闲
}
总线操作完毕
// 返回可能的错误状态
############################################################################### 从机的中断处理函数解析: 读从机中断状态 清从机中断状态
如果有中断继续向下进行 读从机状态 、、如果是主机没有请求任何动作I2C_SLAVE_ACT_NONE 退出 、、如果是主机已发送从机地址和子地址首字节I2C_SLAVE_ACT_RREQ_FBR 读取子地址
退出 、、如果是主机已经发送数据到从机I2C_SLAVE_ACT_RREQ 读取数据 、、如果是主机请求从机发送数据I2C_SLAVE_ACT_TREQ 发送数据 对于32位的编程,一个整体的框架就是:首先是对相关外围模块的使能或者说是时钟的使能,紧接着就是相关端口模块的使能与端口的配置作业,用得到中断的地方要开中断,当然要全部开放的,少一个中断就无法进行,再就是模块的使能了。对于中端处理函数来说,首先是得注册的,这样才能对相关的中端进行处理。具体的中端操作是,读状态,清中断,然后才是相关的处理。
对于UART
函数I2CM_DeviceInitSet( )和I2CM_DeviceDataSet( )用来初始化tI2CM_DEVICE类型的结构体变量。
函数I2CM_Init( )对I2C模块的硬件进行必要的初始化配置,并使能中断。 函数I2CM_SendRecv( )是重要的用户接口函数。器件的数据地址有效长度可能是1~4字节,如果在中断服务函数I2C_ISR( )里直接对长整型的数据成员ulAddr进行操作会显得很笨拙,
因此在该函数里利用switch语句将其转换为一个数组gcAddr[ ],以多字节形式存储器件的数据地址。
在函数I2CM_SendRecv( )里,初始化设置从机地址和第1个要发送的数据后,利用函数I2CMasterControl( )执行命令“主机突发发送起始”,总线动作是“S | SLA+W | data”,这里的data应当是器件的数据存储地址首字节。此时的工作状态是STAT_ADDR(发送数据地址)。在正式启动总线之前,还利用函数I2CMasterBusBusy( )来判断总线是否忙,这可以用来支持多主机通信的情况。剩下的数据收发工作可以由中断服务函数I2C_ISR( )全部自动完成。因此接下来的while循环是在等待总线操作完毕。最后返回可能的错误状态,如被寻址的器件不存在、数据无应答、仲裁失败等。
在中断服务函数I2C_ISR( )里,核心部分是一个长长的switch语句,对3种工作状态STAT_ADDR(发送数据地址)、STAT_DATA(接收或发送数据)和STAT_FINISH(收发完成)分别做出处理。
如果工作状态是STAT_ADDR,表明正处于发送数据地址的状态。如果未发送完毕则继续发送,利用函数I2CMasterControl( )执行命令“主机突发发送继续”;如果发送完毕则工作状态要转为STAT_DATA。进入STAT_DATA状态时又分为3种情况:如果仅接收1个字节的数据,则执行命令“主机单次接收”,并改变工作状态为STAT_FINISH;如果要接收多个字节的数据,则执行命令“主机突发发送起始”;如果是要发送数据,不论是单字节还是多字节,都直接进入下一条case语句,即处理STAT_DATA的状态。
如果工作状态是STAT_DATA,则表明正处于数据接收或发送的状态。如果是接收操作,则用函数I2CMasterDataGet( )读取接收到的数据,然后判断是否准备接收最后1个字节的数据,是则执行命令“主机突发接收完成”,并修改工作状态为STAT_FINISH,否则执行命令“主机突发接收继续”。如果是发送操作,若未发送完毕则继续发送,执行命令“主机突发发送继续”,否则执行命令“主机突发发送完成”,并修改工作状态为STAT_FINISH。
如果工作状态是STAT_FINISH,则表明数据收发工作已经完成,若是接收操作还要读取最后接收到的数据。最后把工作状态变成STAT_IDLE(空闲),以通知主程序收发工作已经完成。
当新接触到一个芯片时,首先,了解其寄存器结构,也是有一定的必要的,当然你也可以跳过此步,倘若有固件库的话,我们可以完全撇开寄存器来进行编程。最好的情况就是能找到固件库中文使用手册,那样就可以减少你啃原版英文资料的时间了,不过可能翻译的不太标准,影响到你的进程,那谁又敢说固件库里边没有说错呢?
正在阅读:
liminary1138学习手记04-18
酶解速溶保健南瓜粉加工技术研究08-20
我与小树共成长作文800字06-21
天津市2019年公需课“不忘初心,牢记使命”的理论与实践逻辑——弘扬爱国奋斗精神,建功立业新时代(答案)06-05
通过亨利的形象分析解读《永别了,武器》中的反战思想07-08
游霍山作文500字06-22
图书管理系统模板05-13
2012版国土整理机械台班定额(完整版)08-15
某县政府办主任述职述廉报告(精选多篇)09-26
挨次志愿与平行志愿的差别 有什么差别03-30
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 手记
- liminary1138
- 学习