msp430单片机的定时模式有哪几种(用MSP430的eUSCI模块的I2C协议读写EEPROM)
msp430单片机的定时模式有哪几种(用MSP430的eUSCI模块的I2C协议读写EEPROM)UCB0I2CSA写入从站地址,设置UCTXSTT标志位(发送START),eUSCI退出复位状态,进入工作模式,eUSCI等待总线空闲,发送START,和Slave Address,然后接收从站返回的数据,数据接收完,发送STOP。主站接收:eUSCI的I2C功能框图主站发送:UCB0I2CSA写入从站地址,设置UCTXSTT标志位(发送START),eUSCI退出复位状态,进入工作模式,eUSCI等待总线空闲,发送START,和Slave Address,以及后续数据,数据发送完后,发送STOP。
本文利用MSP430芯片eUSCI模块的I2C协议,来实现读写24CL04。
eUSCI模块通过SDA SCL与I2C设备相连接,模块主要具有以下功能:
- 7位 和 10位地址可选
- 多主站的收发模式
- 从站收发模式
- 通讯速率从100kbps到400kbps
- 具备字节计数器,自动产生中断和自动发送STOP信号
- 共有4个从站地址,每个都有对应的中断和DMA
本实验将MSP430F6736作为主站,24CL04作为从站。一主一从的模式,比较简单直观。
如果有需要,以后可以做多主对多从的模式。
eUSCI的I2C功能框图
主站发送:
UCB0I2CSA写入从站地址,设置UCTXSTT标志位(发送START),eUSCI退出复位状态,进入工作模式,eUSCI等待总线空闲,发送START,和Slave Address,以及后续数据,数据发送完后,发送STOP。
主站接收:
UCB0I2CSA写入从站地址,设置UCTXSTT标志位(发送START),eUSCI退出复位状态,进入工作模式,eUSCI等待总线空闲,发送START,和Slave Address,然后接收从站返回的数据,数据接收完,发送STOP。
在用I2C读写EEPROM的时候,MCU内相关的寄存器的一些位标志着通讯的状态,可以查询这些状态决定下一步操作。
但本文没有如此操作,因为比较复杂且具有风险,因为等待某标志位的时候必须设定超时,因为通讯不可能没有错误,一旦等不来需要的状态,又没有设定超时,程序很容易陷入死循环,这是绝对不允许发生的。所以采取延时的方式来处理,通讯波特率一旦确定,每个字节传输的时间就可以确定,再加上一点冗余,向发送寄存器写入数据后,等待固定的时间,继续发送下个字节。这样传输过程不会造成死机,数据的纠错可以在整包接收到后进行。
如果网友有更好的方式,欢迎评论留言。
以下为源码和演示视频:
#include "msp430.h"
#include "msp430f6736a.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#define uchar unsigned char
#define uint unsigned int
//---------------------------------
// 初始化MCU
//---------------------------------
void Mcu_Init(void)
{
//---------------------------------
// 初始化系统时钟
//---------------------------------
WDTCTL = WDTPW WDTHOLD; // 禁止看门狗
__bic_SR_register(GIE); // 禁止所有中断
PMMCTL0 = PMMPW PMMCOREV_3;
__delay_cycles(10000);
// 初始化XT1 并使其正常工作
UCSCTL6 &= ~(XT1OFF XT1BYPASS XTS);
UCSCTL6 |= XT1DRIVE_3;
UCSCTL6 |= XCAP_3;
do
{
UCSCTL7 &= ~XT1LFOFFG;
__delay_cycles(30);
} while (UCSCTL7 & XT1LFOFFG);
// XT1CLK作为DCO输入
UCSCTL3 = SELREF__XT1CLK FLLREFDIV__1;
// 禁止 FLL 控制
__bis_SR_register(SCG0);
// DCO=31 MOD=0
UCSCTL0 = 0x1f00;
// DCO 范围: 23.7MHz - 54.1MHz
UCSCTL1 = DCORSEL_5;
// fDCO分频系数D = 2 N = 374
// fDCOCLK = D * (N 1) * FLLRef = 2 * (374 1) * 32768 = 24576000 Hz
UCSCTL2 = FLLD__2 | 374;
// 允许 FLL 控制
__bic_SR_register(SCG0);
__delay_cycles(384000);
do
{
UCSCTL7 &= ~(DCOFFG);
__delay_cycles(30);
} while (UCSCTL7 & DCOFFG);
// ACLK=XT1CLK SMCLK=DCOCLK MCLK=DCOCLK
UCSCTL4 = SELA__XT1CLK SELS__DCOCLK SELM__DCOCLK;
//----------------------------------------------------------
// P2功能【外接信号】 功能 方向 初始值
// P2.1 | PM_UCB0SIMO |【PM_UCB0SDA】| COM7 1[I/O] 1[O] [1]
// P2.0 | PM_UCB0SOMI |【PM_UCB0SCL】| COM6 1[I/O] 1[O] [1]
//----------------------------------------------------------
P2SEL = 0x03;
P2DIR = 0xff;
P2OUT = 0xff;
P2MAP1 = PM_UCB0SDA; // P2.1【PM_UCB0SDA】-> I2C_SDA
P2MAP0 = PM_UCB0SCL; // P2.0【PM_UCB0SCL】-> I2C_SCL
P2REN |= 0x03;
//---------------------------------
// USCI(UCB0)初始化: 用于I2C
//---------------------------------
// USCI(UCB0)->复位状态
UCB0CTLW0 |= UCSWRST;
// I2C模式的Master mode 7bit地址模式 单主设备模式
// 时钟 = SMCLK = 24576000 Hz
UCB0CTLW0 = 0x0F81;
// BPS = 24576000 / 256 = 96000 Hz
UCB0BRW = 256;
}
// BPS=96000 传输一个BYTE时间 = 8/96000 = 83us 延时122us可以保证传输时间足够
#define DELAY_I2C (__delay_cycles(3000)) // 122us = 122 / (1/24.576) = 2998
//---------------------------------
// 写EEPROM(24CL04)
//---------------------------------
void WriteEE(uint EEAddr uchar *RamAddr uint Len)
{
uint i ui_cmd;
if (Len == 0) return;
// USCI(UCB0)->复位状态
UCB0CTLW0 |= UCSWRST;
// Transmitter 模式
UCB0CTLW0 |= UCTR;
// 发送START
UCB0CTLW0 |= UCTXSTT;
// SEND SLAVE ADDRESS
ui_cmd = EEAddr >> 8;
ui_cmd &= 0x0001;
ui_cmd = 0x0050;
UCB0I2CSA = ui_cmd;
// USCI(UCB0)->工作状态
UCB0CTLW0 &= ~UCSWRST;
DELAY_I2C;
// SEND WORD ADDRESS
UCB0TXBUF = EEAddr & 0x00ff;
DELAY_I2C;
for (i=0; i<Len; i )
{
UCB0TXBUF = RamAddr[i];
DELAY_I2C;
}
// 发送STOP
UCB0CTLW0 |= UCTXSTP;
DELAY_I2C;
}
//---------------------------------
// 读EEPROM(24CL04)
//---------------------------------
void ReadEE(uint EEAddr uchar *RamAddr uint Len)
{
uint i ui_cmd;
if (Len == 0) return;
// USCI(UCB0)->复位状态
UCB0CTLW0 |= UCSWRST;
// Transmitter 模式
UCB0CTLW0 |= UCTR;
// 发送START
UCB0CTLW0 |= UCTXSTT;
// SEND SLAVE ADDRESS
ui_cmd = EEAddr >> 8;
ui_cmd &= 0x0001;
ui_cmd = 0x0050;
UCB0I2CSA = ui_cmd;
// USCI(UCB0)->工作状态
UCB0CTLW0 &= ~UCSWRST;
DELAY_I2C;
// SEND WORD ADDRESS
UCB0TXBUF = EEAddr & 0x00ff;
DELAY_I2C;
// 发送STOP
UCB0CTLW0 |= UCTXSTP;
DELAY_I2C;
// USCI(UCB0)->复位状态
UCB0CTLW0 |= UCSWRST;
// Receiver 模式
UCB0CTLW0 &= ~UCTR;
// 发送START
UCB0CTLW0 |= UCTXSTT;
// SEND SLAVE ADDRESS
ui_cmd = EEAddr >> 8;
ui_cmd &= 0x0001;
ui_cmd = 0x0050;
UCB0I2CSA = ui_cmd;
// USCI(UCB0)->工作状态
UCB0CTLW0 &= ~UCSWRST;
DELAY_I2C;
for (i=0; i<Len; i )
{
DELAY_I2C;
if (i == (Len-1))
{ // 发送STOP
UCB0CTLW0 |= UCTXSTP;
}
RamAddr[i] = (uchar)UCB0RXBUF;
}
// 发送STOP
UCB0CTLW0 |= UCTXSTP;
DELAY_I2C;
}
//---------------------------------
// 主流程
//---------------------------------
void main(void)
{
uchar i sbuf[10];
// 初始化MCU
Mcu_Init();
// 初始化LCD
Lcd_Init();
Disp_RomString(Msg_UCB0_I2C LINE1 NORMAL);
Disp_RomString(Msg_WriteEE LINE4 NORMAL);
Disp_RomString(Msg_ReadEE LINE7 NORMAL);
i = 0;
while(1)
{
sbuf[0] = i 0x30;
sbuf[1] = i 0x31;
sbuf[2] = i 0x32;
sbuf[3] = i 0x33;
sbuf[4] = 0;
WriteEE(10 sbuf 4);
Disp_RamString8x16(sbuf LINE4 11 NORMAL);
DELAY_400ms;
memset(sbuf 0 sizeof(sbuf));
ReadEE(10 sbuf 4);
Disp_RamString8x16(sbuf LINE7 11 NORMAL);
DELAY_400ms;
i = (i 1) % 7;
}
}
视频演示内容:先向EEPROM的地址0写入字符串,然后从此地址读出,看是否与写入的内容一致