Matlab生成dsp程序——官方例程学习(5)
官方链接: 官方链接
模型及其程序: 模型及程序
一、基本目的
官方例程中写的是使用IIC与传感器进行通信。因为与具体的官方给的传感器传输协议有一些关系,因此着重看每个模块的功能和大致结构。
二、IIC通信基本原理
IIC通信是两线通信(SDA与SCL),属于半双工的通信方式。I2C协议包括:1.空闲信号 2.开始信号 3.停止信号 4.应答信号 5.数据的有效性 6.数据传输
1)空闲状态
SDA与SCL信号同时处于高电平。
2)起始信号和停止信号
起始信号:SCL为高时,SDA由高到底的跳变。
停止信号:SCL为高时,SDA由低到高的跳变。
3)应答信号
每发送八位,在第九个时钟脉接收应答信号(应答信号为低电平时,表示成功接收,反之亦然),即SCL第九个脉冲之前,必须将SDA拉低。
4)数据有效性
IIC进行数据传送时,SCL为高电平时,SDA必须保持稳定(不允许发生跳变)。只有SCL为低电平时,SDA才能发送变化。
5)数据的传送
SDA每传送一位与一个时钟脉冲进行对应,SCL为高时进行传送。
三、具体实现
因为SDA作为数据线,所有有发送和接收两种状态,相对应需要设置GPIO为输入和输出两种状态。
#define IIC_SCL PBout(6)
#define IIC_SDA PBOUT(7)
#define READ_SDA PBin(7)
void IIC_init() //IIC初始化函数
{
1.设置相应的GPIO管脚的工作模式(开始都置为推挽输出模式)
2.将SCL与SDA置为高电平(进入空闲模式)
}
void IIC_start() //IIC开始信号函数
{
SDA_OUT();
IIC_SDA=1;
IIC_SCL=1;
DELAY_US(10);
IIC_SDA=0; //开始信号完毕
DELAY_US(10);
IIC_SCL=0; //将SCL置为低,开始准备SDA的数据
}
void IIC_stop() //停止信号函数
{
SDA_OUT();
IIC_SDA=0;
IIC_SCL=0;
DELAY_US(10);
IIC_SCL=1;
IIC_SDA=1; //停止信号完毕
DELAY_US(10);
}
int ACK() //接收应答信号
{
int times;
SDA_IN();
IIC_SDA=1;
DELAY_US(10);
IIC_SCL=1;
DELAY_US(10);
while(READ_SDA) //若接收为低电平则不进while,为高 //则继续等待
{
times++;
if(times >250
{
IIC_stop();
return 1;
}
}
IIC_SCL=0;
return0;
}
void IIC_ACK() //发送应答信号(作为接收)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
DELAY_US(10);
IIC_SCL=1;
DELAY_US(10);
IIC_SCL=0;
}
void Send_byte(usigned int t) //发送一个字节
{
int i;
SDA_OUT();
IIC_SCL=0;
for(i=0;i<8;i++)
{
if(t&0x80>>7)
IIC_SDA=1;
else
IIC_SDA=0;
t<<=1;
DELAY_US(10);
IIC_SCL=1;
DELAY_US(10);
IIC_SCL=0;
DELAY_US(10);
}
}
void Rev_bytes()
{
int i;
unsigned char rev=0;
SDA_IN();
for(i=0;i<8;i++)
{
IIC_SCL=0;
DELAY_US(10);
IIC_SCL=1;
rev<<=1;
if(READ_SDA)
rev++;
DELAY_US(10);
}
IIC_ACK(); //发送应答信号
}
以上只是IIC的底层函数,使用还是需要结合具体器件进行查看器件协议。
四、生成代码与模型分析
主要分析一下Timer0中断函数中的程序:
void rt_OneStep(void)
{
boolean_T eventFlags[3];
int_T i;
/* Check base rate for overrun */
if (isRateRunning[0]++) {
IsrOverrun = 1;
isRateRunning[0]--; /* allow future iterations to succeed*/
return;
}
/*
* For a bare-board target (i.e., no operating system), the rates
* that execute this base step are buffered locally to allow for
* overlapping preemption. The generated code includes function
* writeCodeInfoFcn() which sets the rates
* that need to run this time step. The return values are 1 and 0
* for true and false, respectively.
*/
c28x_i2c_sensor_SetEventsForThisBaseStep(eventFlags);
enableTimer0Interrupt();
c28x_i2c_sensor_step0();
/* Get model outputs here */
disableTimer0Interrupt();
isRateRunning[0]--;
for (i = 1; i < 3; i++) {
if (eventFlags[i]) {
if (need2runFlags[i]++) {
IsrOverrun = 1;
need2runFlags[i]--; /* allow future iterations to succeed*/
break;
}
}
}
for (i = 1; i < 3; i++) {
if (isRateRunning[i]) {
/* Yield to higher priority*/
return;
}
if (need2runFlags[i]) {
isRateRunning[i]++;
enableTimer0Interrupt();
/* Step the model for subrate "i" */
switch (i)
{
case 1 :
c28x_i2c_sensor_step1();
/* Get model outputs here */
break;
case 2 :
c28x_i2c_sensor_step2();
/* Get model outputs here */
break;
default :
break;
}
disableTimer0Interrupt();
need2runFlags[i]--;
isRateRunning[i]--;
}
}
}
-
- 建立一个 unsigned int 数组(长度为3)eventFlags[3],建立一个 int 型数据i。
-
- 当isRateRunning[0]大于1时,将IsrOverrun置为1,然后直接退出函数。这里是检验是否满足进入函数的条件。isRateRunning[0]自加1。
-
- 将eventFlags[1]赋值为 (c28x_i2c_sensor_M)->Timing.TaskCounters.TID[1] == 0
-
- 将eventFlags[2]赋值为 (c28x_i2c_sensor_M)->Timing.TaskCounters.TID[2] == 0
-
//c28x_i2c_sensor_M结构体中包含一个errorStatus指针、一个Timing结构体(里面包括TaskCounters结构体(包含一个TID[3])、RateInteraction结构体(包含一个变量TID0_1)) struct tag_RTM_c28x_i2c_sensor { const char_T *errorStatus; /* * Timing: * The following substructure contains information regarding * the timing information for the model. */ struct { struct { uint8_T TID[3]; } TaskCounters; struct { boolean_T TID0_1; } RateInteraction; } Timing; };
-
5)开Timer0中断
-
6)进入**c28x_i2c_sensor_step0()**函数。
-
7)关Timer0中断
-
8)后面的部分指的是,经过判断==eventFlags[i]与need2runFlags[i]以及isRateRunning[i]==的值,先执行c28x_i2c_sensor_step1()、再执行c28x_i2c_sensor_step2()。
下面看**c28x_i2c_sensor_step0()函数,c28x_i2c_sensor_B.I2CReceive_o1[]中存储收到的数据c28x_i2c_sensor_B.I2CReceive_o2中存储受到的变量。8位进行的接收,强制转换为16位数据存放在c28x_i2c_sensor_B.DataTypeConversion[]**中。然后进行发送一个
c28x_i2c_sensor_P.DataReadAdress_Value中的地址。
这一块对应的是模型中这一部分的内容:
**c28x_i2c_sensor_step1()**中对应初始化函数:
**c28x_i2c_sensor_step2()**中对应初始化函数:
五、代码逻辑
step0需要每次循环都执行,即读取数据。然后执行c28x_i2c_sensor_step1()(发送指令)和c28x_i2c_sensor_step2()(转换数据格式)函数。