工具/软件:Code Composer Studio
大家好,
我正在编写一个中断驱动的MSP430 I2C从器,它具有用于记录的实时时钟和电池监视器。 它似乎在"大多数时间"都起作用,但偶尔,当我读取大量数据突发时,一些寄存器返回零,即使它们具有有效数据。 我从DCO运行主环路,频率为1MHz。 如果我将DCO速度提高到8,12或16MHz,我总是得到零....???
我已经实施了一系列可以通过I2C读取或写入的寄存器。
同时,我还在使用LFXTAL来驱动计时器,从连接的32.768kHz xtal生成精确的0.5秒tick。
有什么想法,可能会发生什么?
代码。
谢谢,
Mike。
#include <MSP4S.h>
#在 1上定义
#define off 0
#define true 1.
#define false 0
typedef unsigned char REG_SUBADDR_TYPE;
typedef unsigned char bool;
#define REG_STATUS (REG_SUBADDR_TYPE) 0x00
#define REG_control1 (REG_SUBADDR_TYPE) 0x01
#define REG_Control2 (REG_SUBADDR_TYPE) 0x02
#define REG_BATTERY_HIGH (REG_SUBADDR_TYPE) 0x03
#define REG_BATTERY_LOW (REG_SUBADDR_TYPE) 0x04
#define REG_SW_VERSION (REG_SUBADDR_TYPE) 0x05
#define REG_year (REG_SUBADDR_TYPE) 0x06
#define REG_MONTH (REG_SUBADDR_TYPE) 0x07
#define REG_DATE (REG_SUBADDR_TYPE) 0x08
#define REG_Hour (REG_SUBADDR_TYPE) 0x09
#define REG_MINUTE (REG_SUBADDR_TYPE) 0x0A
#define REG_second (REG_SUBADDR_TYPE) 0x0B
#define REG_ALARM_year (REG_SUBADDR_TYPE) 0x0C
#define REG_ALARM_MONTH (REG_SUBADDR_TYPE) 0x0D
#define REG_ALARM_DATE (REG_SUBADDR_TYPE) 0x0E
#define REG_ALARM_Hour (REG_SUBADDR_TYPE) 0x0F
#define REG_ALARM_MINUTE (REG_SUBADDR_TYPE) 0x10
#define REG_ALARM_seconds (REG_SUBADDR_TYPE) 0x1A
typedef枚举
{
IIC_SLAVE_IDLE,
IIC_SLAVE_RXED_SLAVE_ADDR,
IIC_SLAVER_SLAVER_TX_BLOCK,
IIC_SLAVER_SLAVER_RX_BLOCK
} IIC_SLAVER_STANE_TYPE;
静态IIC_SLAVE_STATE_TYPE IIC_SLAVE_STATE; //I2C状态
REG_SUBADDR_TYPE IIC_REG_ADDRESS; //当前寄存器指针
static unsigned char battery_leve_high = 0x00;
static unsigned char battery_leve_low = 0x00;
静态无符号int reg_year =17;
静态无符号int reg_month =2;
静态无符号int reg_date =28;
静态无符号int reg_hours =15;
静态无符号int reg_minutes =30;
静态无符号int reg_seconds =30;
静态无符号int reg_alarm_year = 17;
静态无符号int reg_alarm_month=2;
静态无符号int reg_alarm_date = 28;
静态无符号int reg_alarm_hours =16;
静态无符号int reg_alarm_minutes =30;
静态无符号int reg_alarm_seconds = 30;
//声明函数原型
void delay ( unsigned int );
void Update_Half_seconds (void);
void Update_Clock_24hr (void);
void Update_Display(void);
void Update_Mode (void);
作废Check_Alarm (void);
作废Check_Battery (作废);
int REG_READ_REGISTER (REG_SUBADDR_TYPE);
int REG_WRITE注册(REG_SUBADDR_TYPE,int);
REG_SUBADDR_TYPE REG_INC_REGISTER_REG(REG_SUBADDR_TYPE);
内部主(无效)
{
WDTCTL = WDTPW | WDTHOLD; //停止看门狗计时器
IF (CALC1_1MHz == 0xFF || CALDCO_1MHz == 0xFF)
{
while (1); //如果校准常量被擦除,则停止
}
//1MHz
BCSCTL1 = CALC1_1MHz; //设置范围
DCOCTL = CALDCO_1MHz; //设置DCO步进+调制*
//BCSCTL2 |= DIVS1 + DIVS0; // SMCLK /8除法器
BCSCTL3 = 0x0C; // 32.768kHz,12.5pF负载盖
P3SEL |= 0x06; //将I2C引脚分配给USI_B0
UCB0CTL1 || UCSWRST; //将USCI逻辑置于重置状态,SMCLK
UCB0CTL0 = UCMODE_3 + UCSYNC; // USCI = I2C,同步模式
UCB0I2COA = 0x18; //自有地址为0x18
UCB0CTL1 &=~UCSWRST; //释放USCI逻辑重置
UCB0I2CIE || UCSTPIE + UCSTTIE; //启用STT和STP中断
IE2 |= UCB0RXIE + UCB0TXIE; //启用RX和TX中断
IIC_SLAVE_STATE = IIC_SLAVE_IDLE; //初始化I2C状态机
P1DIR = 0x3D;
P1OUT = 0x00;
P2DIR = 0x20; //WFP 2.5 作为OP
P2IE |= 0x18; //已启用WFP 2.3 ,WFP 2.4 中断
P2IES |= 0x18; //高/低边缘
P2IFG &=~0x18; // IFG已清除
P2OUT |= BIT5; //debug -打开5V_AUX_EN以启用DC-DC
P3DIR |= 0xF9;
P3OUT = 0x00;
TA1CTL = tassel_1 + MC_1; // ACLK (32.678kHz),上行模式
TA1CCR0 = 0x3FFF; // 3FFF相当于32.768kHz时的0.5秒
TA1CCTL0 = CCIE; //已启用TACR0中断
__enable_interrupit();
//__bis_sr_register(CPUOFF + GIE); //输入带中断的LPM0
同时(1);
}
//------------------
//此处处理I2C总线状态更改中断
//当UCB0TXBUF加载了一个字节时,Tx IFG被清除
//读取UCB0RXBUF时清除Rx IFG
//------------------
#pragma vector = USCIAB0TX_vector
__interrupt void USCIAB0TX_ISR(void)
{
如果(IFG2和UCB0RXIFG) //主中继正在给我们写信
{
如果(IIC_SLAVE_STA= IIC_SLAVE_IDLE) //如果我们处于空闲状态,则注册主机要读取或写入
{
IIC_REG_ADDRESS = UCB0RXBUF; //将是子地址
IIC_SLAVE_STANE = IIC_SLAVE_RXED_SLAVE_ADDR; //移至下一状态
}
否则,如果(IIC_SLAVE_STA= IIC_SLAVER_RXED_SLAVER_ADDR)
{
REG_WRITE_REGISTER (IIC_REG_ADDRESS,UCB0RXBUF);
IIC_REG_ADaddress =(REG_SUBADDR_TYPE) REG_INC_REGISTER (IIC_REG_ADDRESS); //计算下一个地址
}
}
else //else,Master要读取数据
{
UCB0TXBUF = REG_READ_REGISTER (IIC_REG_ADDRESS); //加载先前设置的子地址的内容
IIC_REG_ADaddress =(REG_SUBADDR_TYPE) REG_INC_REGISTER (IIC_REG_ADDRESS); //计算下一个地址
}
}
//------------------
//此处处理I2C总线状态更改中断
//------------------
#pragma vector = USCIAB0RX_vector
__interrupt void USCIAB0RX_ISR(void)
{
IF (UCB0STAT和UCSTPIFG)//如果停止INT
{
IIC_SLAVER_STANE = IIC_SLAVE_IDLE;
IIC_REG_ADDRESS = 0x00;
UCB0STAT &=~UPSTPIFG;
}
否则,如果(UCB0STAT和UCSTIFG)//如果启动INT
{
UCB0STAT &=~UCSTIFG;
}
}
空延迟(无符号int ms)
{
同时(毫秒--)
{
__DELAY周期(1000);//设置为16MHz,将其更改为1000,设置为1 MHz
}
}
// Timer1_A0中断服务例程
#pragma vector=Timer1_A0_vector
__interrupt void Timer1_A0 (void)
{
update_half_seconds();
}
/*此函数应每隔1/512秒从interupt*/中调用一次
/*此中断中的所有功能应在1毫秒内完成,因此不禁用中断!*/
作废Update_Half_Seconds (void)
{
static char half_seconds = 0;
P3OUT ^= BIT6; //调试:闪烁绿色LED
半秒++;
如果(Half_seconds>=2)
{
UPDATE_Clock_24hr();
Half_seconds=0;
}
}
/*这是唯一更新实际实时的函数*/
/*此函数应每秒调用一次*/
作废Update_Clock_24hr (void)
{
REG_seconds++;
Check_Alarm(); //如果位已设置,请检查是否有报警
如果(REG_seconds >= 60)
{
REG_seconds =0; //重置REG_seconds
REG_MINUTES ++;
如果(REG_MINUTES >= 60)
{
REG_MINUTES = 0;
REG_Hours++;
}
如果(REG_Hours >= 24)
{
REG_Hours = 0;
}
CHECK_BATTERY();// 电池电压每分钟更新一次
}
}
/*每次更新REG_MINUTES计数器时都会调用此函数
*
*/
作废Check_Battery (作废)
{
静态长ADC_Temp = 0.0 ;
ADC10CTL1 = inch_1; /CH1.
ADC10CTL0 = SREF_1 + ADC10SHT_2 + RefoN + Ref2_5V + ADC10ON; //VREF,16 ADC CLK,2.5V REF ON,
P3OUT|= BIT3; //打开电池ADC路径
延迟(5); //稳定时间
ADC10CTL0 |= ENC + ADC10SC; //开始采样和转换
当(ADC10CTL1和占线); //等待ADC10完成
ADC_Temp = ADC10MEM; //指定ADC10MEM中保留的值
P3OUT &=~BIT3; //关闭电池ADC路径
BATTERY_LEVE_LOW =(ADC_Temp & 0x00FF); //存储较低位
BATTERY_LEVE_HIGH =(ADC_Temp >> 8); //向右移动并存储高位
IF (ADC_Temp >= 302) //4.2V
{
;
}
否则,如果((ADC_Temp >= 259)&&(ADC_Temp <= 301)//3.6V->4.2V
{
;
}
否则,如果((ADC_Temp >= 223)&&(ADC_Temp <= 258)//3.1V-->3.6V
{
;
}
否则,如果( ADC_Temp <=216) //<3.1伏
{
;
}
}
/*每次更新REG_MINUTES计数器时都会调用此函数
*
*/
作废Check_Alarm (作废)
{
如果(REG_Hours == REG_ALARM_Hours)&&(REG_MINUTES == REG_ALARM_MINUTES)&&
(REG_seconds == REG_ALARM_seconds)
{
;
}
}
/*I2C读取寄存器功能
*
*/
int REG_READ_REGISTER (REG_SUBADDR_TYPE 子地址)
{
交换机(subaddr)
{
案例REG_BATTERY_LOW:
返回电池电量低;
案例REG_BATTERY_HIGH:
返回电池电量_水平_高;
案例REG_SW_VERSION:
返回0x01;
案例REG_year:
返回REG_year;
案例REG_MONTH:
返回reg_month;
案例REG_DATE:
返回reg_date;
案例REG_Hour:
返回REG_Hours;
案例REG_MINUTE:
返回REG_MINUTES;
案例REG_ST秒:
返回REG_seconds;
案例REG_ALARM_year:
返回reg_alarm_year;
案例REG_ALARM_MONTH:
返回reg_alarm_month;
案例REG_ALARM_DATE:
返回reg_alarm_date;
病例REG_ALARM_Hour:
返回REG_ALARM_Hours;
病例REG_ALARM_MINUTE:
返回REG_ALARM_MINUTES;
病例REG_ALARM_seconds:
返回REG_ALARM_seconds;
默认:
返回0;
}
}
/* I2C写入寄存器功能
*
*/
int REG_WRITE注册(REG_SUBADDR_TYPE子地址,int值)
{
交换机(subaddr)
{
案例REG_BATTERY_LOW:
返回false;
案例REG_BATTERY_HIGH:
返回false;
案例REG_SW_VERSION:
返回false;
案例REG_year:
REG_year =值;
返回true;
案例REG_MONTH:
REG_MONTH =值;
返回true;
案例REG_DATE:
REG_DATE =值;
返回true;
案例REG_Hour:
REG_Hours =值;
返回true;
案例REG_MINUTE:
REG_MINUTES =值;
返回true;
案例REG_ST秒:
REG_seconds =值;
返回true;
案例REG_ALARM_year:
REG_ALARM_year =值;
返回true;
案例REG_ALARM_MONTH:
REG_ALARM_MONTH =值;
返回true;
案例REG_ALARM_DATE:
REG_ALARM_DATE =值;
返回true;
病例REG_ALARM_Hour:
REG_ALARM_Hours =值;
返回true;
病例REG_ALARM_MINUTE:
REG_ALARM_MINUTES =值;
返回true;
病例REG_ALARM_seconds:
REG_ALARM_seconds =值;
返回true;
默认:
返回false;
}
}
/*确定组中的下一个I2C寄存器
*
*/
REG_SUBADDR_TYPE REG_INC_REGISTER (REG_SUBADDR_TYPE子地址)
{
交换机(subaddr)
{
案例0x00:RETURN (REG_SUBADDR_TYPE)(0x03); //保留
案例0x01:RETURN (REG_SUBADDR_TYPE)(0x03); //保留
案例0x02:RETURN (REG_SUBADDR_TYPE)(0x03); //保留
案例0x03:返回(REG_SUBADDR_TYPE)(0x04); //电池电量高
案例0x04:返回(REG_SUBADDR_TYPE)(0x03); //电池电量低
案例0x05:RETURN (REG_SUBADDR_TYPE)(0x05); // FW版本
案例0x06:RETURN (REG_SUBADDR_TYPE)(0x07); //年
案例0x07:RETURN (REG_SUBADDR_TYPE)(0x08); //月
案例0x08:RETURN (REG_SUBADDR_TYPE)(0x09); //日期
案例0x09:RETURN (REG_SUBADDR_TYPE)(0x0A); // Hour
案例0x0A:RETURN (REG_SUBADDR_TYPE)(0x0B); //分钟
案例0x0B:RETURN (REG_SUBADDR_TYPE)(0x06); //第二个
案例0x0C:RETURN (REG_SUBADDR_TYPE)(0x0D); // Alarm_Year
案例0x0D:REG_SUBADDR_TYPE (0x0E); // Alarm_Month
案例0x0E:REG_SUBADDR_TYPE (0x0F); // Alarm_Date
案例0x0F:REG_SUBADDR_TYPE (0x10); // Alarm_Hour
案例0x10:REG_SUBADDR_TYPE (0x11); // Alarm_Minute
案例0x11:RETURN (REG_SUBADDR_TYPE)(0x0C); // Alarm_Second
}
RETURN(REG_SUBADDR_TYPE)(子地址); /*否则我们将返回相同的寄存器! */
}