msp430单片机模拟IIC总线读取MMA7660三轴加速度传感器
[复制链接]
搞了几天的msp430单片机,发现它的硬件IIC并不是很好用(没调出来,嘿嘿),所以就弃之不用了,改用模拟IIC总线的协议。用来读取MMA7660三轴加速度按传感器的X,Y,Z的值,并通过串口显示出来,串口也是通过定时器TimerA模拟来的,只是为了练习一下单片机的编程所以都用了模拟。测试结果如下:
代码如下:
file1 :main.c
#include "msp430G2452.h"
#include "g2452uart.h"
#include "MMA7660FC.h"
#define SDA_DirOut P2DIR |= BIT0
#define SDA_DirIn P2DIR &=~ BIT0
#define SDA_0 P2OUT &=~ BIT0
#define SDA_1 P2OUT |= BIT0
#define SCL_1 P2OUT |= BIT1
#define SCL_0 P2OUT &=~ BIT1
#define Get_Bit( x,y) ((x&(1<<y))==0? 0="" :="" 1="" )
#define SDA_in Get_Bit(P2IN,0)
char X_value=0 ;
char Y_value=0 ;
char Z_value=0 ;
signed char X_value_final,Y_value_final,Z_value_final; //三轴加速度的最终值,有正负
void OSC_Init()
{
WDTCTL=WDTPW+WDTHOLD;//close whatchdog
if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
{
while(1); // If calibration constants erased
// do not load, trap CPU!!
}
//1Mhz
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation */
}
void Port_Init()
{
P2DIR |= BIT0+BIT1;
SDA_1;
SCL_1;
}
void delay_us( unsigned int k )
{
while(k--)
_nop();
}
void IIC_Start()
{
SDA_1;
SCL_1;
delay_us(5);
SDA_0; //产生下降沿
delay_us(5);
SCL_0; //拉低时钟线,准备发送或者接收数据
}
void IIC_Stop()
{
SCL_1;
SDA_0;
delay_us(5);
SDA_1; //产生一个上升沿
delay_us(5);
}
void IIC_SendAck()
{
SDA_0;
SCL_1;
delay_us(5);
SCL_0;
delay_us(5);
}
void IIC_SendNAck()
{
SDA_1;
SCL_1;
delay_us(5);
SCL_0;
delay_us(5);
}
unsigned char IIC_RecAck()
{
unsigned char CY ;
SDA_DirIn; //在接收模式下,设置SDA的方向为输入
SCL_1; //拉高时钟线
delay_us(5); //延时
CY = SDA_in; //读应答信号
SCL_0 ; //拉低时钟线
delay_us(5); //延时
SDA_DirOut; //接收结束的时候还要吧SDA的方向切换过来
return CY;
}
void IIC_WriteByte(unsigned int data)
{
unsigned char i ;
for (i=0;i<8;i++)
{
if((data&0x80)?1:0) //分别发送每一位二进制数据
SDA_1;
else
SDA_0 ;
SCL_1;
data<<=1; //移位传送下一位
delay_us(5);
SCL_0; //在SCL上升沿的时候加载一位的数据
delay_us (5);
}
SDA_1; //8位数据位发送完释放数据总线,同时SDA拉高
// IIC_Recevie(); //接收答信号
}
unsigned char IIC_Read(void )
{
unsigned char i ,data=0;
SDA_DirIn; //在接收模式下,设置SDA的方向为输入
for (i=0;i<8;i++)
{
SCL_0;
delay_us(5);
SCL_1 ; //SCL下降沿期间有数据,当SCL为高时数据线上的数据才有效
data<<=1;
data|=SDA_in;
delay_us(3);
}
SDA_DirOut; //接收结束的时候还要吧SDA的方向切换过来
return data;
}
void WriteToAddr(unsigned char REG_addr, unsigned char REG_data )
{
IIC_Start();
IIC_WriteByte(SlaveAddress+0); //发送从机地址+写入操作0
IIC_RecAck(); //应答
IIC_WriteByte(REG_addr); //写入内部寄存器地址
IIC_WriteByte(REG_data); //写入内部寄存器数据
IIC_RecAck();
IIC_Stop();
delay_us(5);
}
unsigned char ReadFromAddr(unsigned char REG_addr)
{
unsigned char RecData ;
IIC_Start(); //启动IIC总线
IIC_WriteByte(SlaveAddress+0); //写入从机地址+写命令0
IIC_WriteByte(REG_addr); //写入要读的内部寄存器地址
IIC_Start();
IIC_WriteByte(SlaveAddress+1); //写入从机地址+读命令1
RecData=IIC_Read();
IIC_SendNAck();
IIC_Stop();
return RecData;
}
void MMA7660_Init()
{
WriteToAddr(MMA7660_MODE,0x01);
}
void Read3axle(void)
{
X_value=ReadFromAddr(X_outAddr);
Y_value=ReadFromAddr(Y_outAddr);
Z_value=ReadFromAddr(X_outAddr);
//将采集到的数据转换到-32~31之间
X_value_final=(char)(X_value<<2);
X_value_final =(char)(X_value_final /4);
Y_value_final= (char)(Y_value<<2);
Y_value_final = (char)(Y_value_final /4);
Z_value_final= (char)(Z_value<<2);
Z_value_final = (char)(Z_value_final /4);
}
//-----------主函数-----------------------------------------------------------
void main(void)
{
OSC_Init();
Port_Init();
TimerA_UART_init();
MMA7660_Init();
__enable_interrupt();
TimerA_UART_print("All Initialization is OK!");
for (;;)
{
//__bis_SR_register(LPM0_bits);
Read3axle();
if (X_value_final>0)
P1OUT|= BIT0;
else if(X_value_final<0)
P1OUT&=~ BIT0;
else _nop();
//------------------------------
TimerA_UART_print("X_value---->");
output((unsigned int )X_value,4);
TimerA_UART_print(" ");
//------------------------------
TimerA_UART_print("Y_value---->");
output((unsigned int )Y_value,4);
TimerA_UART_print(" ");
//------------------------------
TimerA_UART_print("Z_value---->");
output((unsigned int )Z_value,4);
TimerA_UART_print("");
//------------------------------
P1OUT ^= BIT6 ;
//delay_us(20000);
}
}
//-------------------华丽的分割线-----------------------------------------------------------------
//file2 : g2452uart.h
#include "msp430g2452.h"
//------------------------------------------------------------------------------
// Hardware-related definitions
//------------------------------------------------------------------------------
#define UART_TXD 0x02 // TXD on P1.1 (Timer0_A.OUT0)
#define UART_RXD 0x04 // RXD on P1.2 (Timer0_A.CCI1A)
//------------------------------------------------------------------------------
// Conditions for 9600 Baud SW UART, SMCLK = 1MHz
//------------------------------------------------------------------------------
#define UART_TBIT_DIV_2 (1000000 / (9600 * 2))
#define UART_TBIT (1000000 / 9600)
//------------------------------------------------------------------------------
// Global variables used for full-duplex UART communication
//------------------------------------------------------------------------------
unsigned int txData; // UART internal variable for TX
unsigned char rxBuffer; // Received UART character
//------------------------------------------------------------------------------
// 串口通信的接口函数说明:
//------------------------------------------------------------------------------
void TimerA_UART_init(void);
//TimerA_UART_init()模拟串口通信初始化函数,在main()函数中调用此函数就可以使用一下两个函数了
void TimerA_UART_tx(unsigned char byte);
//TimerA_UART_tx( byte ) 通过串口发送一字节的数据
void TimerA_UART_print(char *string);
//TimerA_UART_print(*string) 通过串口发送任意字节的字符穿
void output(unsigned int num , int n );
//输出一个数字
//注:接收的一字节数据存在rxBuffer变量里。
void Port1_Init()
{
P1OUT = 0x00; // Initialize all GPIO
P1SEL = UART_TXD + UART_RXD; // Timer function for TXD/RXD pins
// P1DIR = 0xFF & ~UART_RXD; // Set all pins but RXD to output
//设置TXD为输出模式,P1.1和P1.2两个调试小灯也为输出模式。RXD为输入模式。
P1DIR |= UART_TXD+BIT0+BIT6;
P1DIR &=~ UART_RXD;
P1OUT &=~ BIT0+BIT6 ; //初始化让两个灯都灭。
}
//------------------------------------------------------------------------------
// Function configures Timer_A for full-duplex UART operation
//------------------------------------------------------------------------------
void TimerA_UART_init(void)
{
Port1_Init(); //P1端口初始化!
TACCTL0 = OUT; // Set TXD Idle as Mark = '1'
TACCTL1 = SCS + CM1 + CAP + CCIE; // Sync, Neg Edge, Capture, Int
TACTL = TASSEL_2 + MC_2; // SMCLK, start in continuous mode
}
//------------------------------------------------------------------------------
// Outputs one byte using the Timer_A UART
//------------------------------------------------------------------------------
void TimerA_UART_tx(unsigned char byte)
{
while (TACCTL0 & CCIE); // Ensure last char got TX'd
TACCR0 = TAR; // Current state of TA counter
TACCR0 += UART_TBIT; // One bit time till first bit
TACCTL0 = OUTMOD0 + CCIE; // Set TXD on EQU0, Int
txData = byte; // Load global variable
txData |= 0x100; // Add mark stop bit to TXData
txData <<= 1; // Add space start bit
}
//------------------------------------------------------------------------------
// Prints a string over using the Timer_A UART
//------------------------------------------------------------------------------
void TimerA_UART_print(char *string)
{
while (*string) {
TimerA_UART_tx(*string++);
}
}
void output(unsigned int num , int n )
{
char *p,pd[4];
p=pd;
pd[0]=num/1000 +48 ; //千位
pd[1]=num/100 +48 ;// 百位
pd[2]=num0/10 +48 ; //十位
pd[3]=num +48;//个位
while (n--)
TimerA_UART_tx((*p++));
}
//------------------------------------------------------------------------------
// Timer_A UART - Transmit Interrupt Handler
//------------------------------------------------------------------------------
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0_ISR(void)
{
static unsigned char txBitCnt = 10;
TACCR0 += UART_TBIT; // Add Offset to CCRx
if (txBitCnt == 0) { // All bits TXed?
TACCTL0 &= ~CCIE; // All bits TXed, disable interrupt
txBitCnt = 10; // Re-load bit counter
}
else {
if (txData & 0x01) {
TACCTL0 &= ~OUTMOD2; // TX Mark '1'
}
else {
TACCTL0 |= OUTMOD2; // TX Space '0'
}
txData >>= 1;
txBitCnt--;
}
}
//------------------------------------------------------------------------------
// Timer_A UART - Receive Interrupt Handler
//------------------------------------------------------------------------------
#pragma vector = TIMER0_A1_VECTOR
__interrupt void Timer_A1_ISR(void)
{
static unsigned char rxBitCnt = 8;
static unsigned char rxData = 0;
switch (__even_in_range(TA0IV, TA0IV_TAIFG)) { // Use calculated branching
case TA0IV_TACCR1: // TACCR1 CCIFG - UART RX
TACCR1 += UART_TBIT; // Add Offset to CCRx
if (TACCTL1 & CAP) { // Capture mode = start bit edge
TACCTL1 &= ~CAP; // Switch capture to compare mode
TACCR1 += UART_TBIT_DIV_2; // Point CCRx to middle of D0
}
else {
rxData >>= 1;
if (TACCTL1 & SCCI) { // Get bit waiting in receive latch
rxData |= 0x80;
}
rxBitCnt--;
if (rxBitCnt == 0) { // All bits RXed?
rxBuffer = rxData; // Store in global variable
rxBitCnt = 8; // Re-load bit counter
TACCTL1 |= CAP; // Switch compare to capture mode
//__bic_SR_register_on_exit(LPM0_bits); // Clear LPM0 bits from 0(SR)
}
}
break;
}
}
//----------------------华丽的分割线2--------------------------------------------------------
//file :MMA7660FC.h
#ifndef _MMA7660FC_H
#define _MMA7660FC_H
#define MMA7660FC_ADD 0x4C //Please contact the factory to request a different IIC address
#define MMA7660FC_MW_ADD 0x98 //master write address
#define MMA7660FC_MR_ADD 0x99 //master read address
#define SlaveAddress 0x98 //从机地址
#define X_outAddr 0x00
#define Y_outAddr 0x01
#define Z_outAddr 0x02
// IIC Register Address
#define MMA7660_XOUT 0x00
#define MMA7660_YOUT 0x01
#define MMA7660_ZOUT 0x02
#define MMA7660_TILT 0x03
#define MMA7660_SRST 0x04
#define MMA7660_SPCNT 0x05
#define MMA7660_INTSU 0x06
#define MMA7660_MODE 0x07
#define MMA7660_SR 0x08
#define MMA7660_PDET 0x09
#define MMA7660_PD 0x0A
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//以上为所有程序源码!编译工具CCS V5.0 复制代码