caobingluo 发表于 2011-10-3 15:18:35

贴上程序 欢迎指教

#include <compiler_defs.h>
#include <C8051F990_defs.h>            // SFR declarations
#include "adxl.h"

//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------

#defineSYSCLK         24500000       // System clock frequency in Hz


#defineSMB_FREQUENCY10000          // Target SCL clock rate
                                       // This example supports between 10kHz
                                       // and 100kHz
#define BAUDRATE      9600      // Baud rate of UART in bps
#defineWRITE          0x00         // SMBus WRITE command
#defineREAD         0x01         // SMBus READ command

#define LED_ON         0             // Turns the LED on
#define LED_OFF          1             // Turns the LED off

// Device addresses (7 bits, LSB is a don't care)
#defineSLAVE_ADDR   0xA6         // Device address for slave target

// Status vector - top 4 bits only
#defineSMB_MTSTA      0xE0         // (MT) start transmitted
#defineSMB_MTDB       0xC0         // (MT) data byte transmitted
#defineSMB_MRDB       0x80         // (MR) data byte received
// End status vector definition

//-----------------------------------------------------------------------------
// Global VARIABLES
//-----------------------------------------------------------------------------
U8 SMB_DATA_IN;                        // Global holder for SMBus data
                                       // All receive data is written here

U8 SMB_DATA_OUT;                     // Global holder for SMBus data.
                                       // All transmit data is read from here

U8 TARGET=0XA6;                           // Target SMBus slave address

volatile bit SMB_BUSY;               // Software flag to indicate when the
                                       // SMB_Read() or SMB_Write() functions
                                       // have claimed the SMBus

volatile bit SMB_RW;                   // Software flag to indicate the
                                       // direction of the current transfer

U16 NUM_ERRORS;                        // Counter for the number of errors.

SBIT (YELLOW_LED, SFR_P1, 3);          // YELLOW_LED==LED_ON means ON

SBIT (SDA, SFR_P0, 0);               // SMBus on P0.0
SBIT (SCL, SFR_P0, 1);               // and P0.1

LOCATED_VARIABLE_NO_INIT (reserved, U8, SEG_XDATA, 0x0000);
bit byte1,byte2,byte3;//表示有效的字节
char x,y,z;//分别存储传过来的
int x_data,y_data,z_data;
char send_data1,send_data2,send_data3;
char rec_data1,rec_data2;
char test;
unsigned char P3;

U8 TX_Ready =1;
// SMBus Interrupt Service Routine (ISR)
//-----------------------------------------------------------------------------
//
// SMBus ISR state machine
// - Master only implementation - no slave or arbitration states defined
// - All incoming data is written to global variable <SMB_DATA_IN>
// - All outgoing data is read from global variable <SMB_DATA_OUT>
//
//-----------------------------------------------------------------------------

INTERRUPT(SMBUS0_ISR, INTERRUPT_SMBUS0)
{
   bit FAIL = 0;                     // Used by the ISR to flag failed
                                       // transfers
   static bit ADDR_SEND = 0;         // Used by the ISR to flag byte
                                       // transmissions as slave addresses

   if (ARBLOST == 0)                   // Check for errors
   {
      // Normal operation
      switch (SMB0CN & 0xF0)         // Status vector
      {
         // Master Transmitter/Receiver: START condition transmitted.
         case SMB_MTSTA:
                //        if(SMB_RW==0)
            SMB0DAT = TARGET;          // Load address of the target slave
            SMB0DAT &= 0xFE;         // Clear the LSB of the address for the
         //   else                        // R/W bit
                        SMB0DAT |= SMB_RW;         // Load R/W bit
            STA = 0;                   // Manually clear START bit
            ADDR_SEND = 1;
            break;

         // Master Transmitter: Data byte transmitted
         case SMB_MTDB:
            if (ACK)                   // Slave ACK?
            {
               SMB0DAT=send_data1;//要送的数据
                           byte1=0; //第一个数据已经送出去了
                           if(byte2==1)
                                                {
                                                        SMB0DAT=send_data2;//要送的数据
                                                        byte2=0;
                                                }
                                else if (byte3==1)
                                                {
                                                        SMB0DAT=send_data3;
                                                        byte3=0;       
                                                }
                                else //已经全送完了则结束
                                                {
                                                        STO=1;//结束
                                                        SMB_BUSY=0;
                                                }
                                break;
            }
            else                     // If slave NACK,
            {SMB0DAT=send_data1;//重新发送
             //STO = 1;                // Send STOP condition, followed
            // STA = 1;                // By a START
             //NUM_ERRORS++;         // Indicate error
                           break;

            }
            
         // Master Receiver: byte received
         case SMB_MRDB:
            if (ACK)                   // Slave ACK?
            {
               if(byte1==1)
                                                {
                                                        rec_data1=SMB0DAT;
                                                        byte1=0;
                                                        if(byte2==1)
                                                               SMB0ADM|=0x01;
                                                        else SMB0ADM|=0x00;                                                       
                                          }
                                                else if(byte2==1)
                                                {       
                                                        rec_data2=SMB0DAT;
                                                        byte2=0;
                                                        SMB0ADM|=0x00;
                                                }
                                                else
                                                        SMB0ADM|=0x00;
                                                break;
            }
            else                     // If slave NACK,
            {
                        //SMB0DAT=send_data1;//重新发送
               STO=1;
                        SMB_BUSY=0;
                                break;
            }
         
         default:
            FAIL = 1;                  // Indicate failed transfer
                                       // and handle at end of ISR
            break;

      } // end switch
   }
   else
   {
      // ARBLOST = 1, error occurred... abort transmission
      FAIL = 1;
   } // end ARBLOST if

   if (FAIL)                           // If the transfer failed,
   {
      SMB0CF &= ~0x80;               // Reset communication
      SMB0CF |= 0x80;
      STA = 0;
      STO = 0;
      ACK = 0;

      SMB_BUSY = 0;                  // Free SMBus

      FAIL = 0;
      YELLOW_LED = LED_OFF;

      NUM_ERRORS++;                  // Indicate an error occurred
   }

   SI = 0;                           // Clear interrupt flag
}

//-----------------------------------------------------------------------------
// Timer3 Interrupt Service Routine (ISR)
//-----------------------------------------------------------------------------
//
// A Timer3 interrupt indicates an SMBus SCL low timeout.
// The SMBus is disabled and re-enabled here
//
//-----------------------------------------------------------------------------
INTERRUPT(TIMER3_ISR, INTERRUPT_TIMER3)
{
   SMB0CF &= ~0x80;                  // Disable SMBus
   SMB0CF |= 0x80;                     // Re-enable SMBus
   TMR3CN &= ~0x80;                  // Clear Timer3 interrupt-pending flag
   STA = 0;
   SMB_BUSY = 0;                     // Free SMBus
}



void Send_single(char reg_addr,char send_data)
{       
        while(SMB_BUSY);
       SMB_BUSY=1;
       SMB0CF |= 0x80;
       SMB0ADM|=0x01;
       
       //SMB0CN=0xC0;
       SMB_RW=0;//write
       byte1=1;
       byte2=1;
       byte3=0;
        send_data1=reg_addr;//第一比特数据是要写的寄存器的地址
        send_data2=send_data;
        STA=1;//要写的东西配置完了然后启动一次传输       
}



void Send_double(char reg_addr,char data1,char data2)
{
        while(SMB_BUSY);
        SMB_BUSY=1;
       SMB0CF |= 0x80;
       SMB0ADM|=0x01;
//        SMB0CN=0x44;
        SMB_RW=0;
        byte1=1;
       byte2=1;
       byte3=1;
        send_data1=reg_addr;

        send_data2=data1;
        send_data3=data2;
        STA=1;
}




void Rec_single(char reg_addr,char *data1)
{
        while(SMB_BUSY);
        SMB_BUSY=1;
        SMB0CF |= 0x80;
        SMB0ADM|=0x01;
//        SMB0CN=0x44;
        SMB_RW=0;
        byte1=1;
       byte2=0;
       byte3=0;
        send_data1=reg_addr;
        STA=1;
        while(SMB_BUSY);
        SMB_BUSY=1;
        SMB_RW=1;
        byte1=1;
       byte2=0;
       byte3=0;
        STA=1;
        while(SMB_BUSY);
        *data1=rec_data1;
}

void Rec_double(char reg_addr,char *data1,char *data2) //datasheet说最好支持突发读(多字节读)
{
        while(SMB_BUSY);
        SMB_BUSY=1;
        SMB0CF |= 0x80;
        SMB0ADM|=0x01;
//        SMB0CN=0x44;
        send_data1=reg_addr;
        SMB_RW=0;
        byte1=1;
        byte2=0;
        byte3=0;
        STA=1;
        while(SMB_BUSY);
        SMB_BUSY=1;
        SMB_RW=1;
//        SMB0CN=0X44;
        byte1=1;
        byte2=1;
        byte3=0;//两个比特
        STA=1;       
        while(SMB_BUSY);
        *data1=rec_data1;
        *data2=rec_data2;
}

void uart0() interrupt         4
{
                TI0=0;//接收结束

}

void uart_int(unsigned int a)//专门用来传13位数的
{
        if(a>0x1000)
        {
                a=0x2000-a;//转换为补码,输出符号
                SBUF0='-';
                while(TI0==0);
                TI0=0;
        }
       
        SBUF0=a/1000+'0';
        while(TI0==0);
        TI0=0;        
        a%=1000;
        SBUF0=a/100+'0';
        while(TI0==0);
        TI0=0;        
        a%=100;
        SBUF0=a/10+'0';
        while(TI0==0);
        TI0=0;        
        a%=10;
        SBUF0=a+'0';
        while(TI0==0);
        TI0=0;
}

void int0() interrupt 0
{
       
        /*                 Rec_double(OFSX,&x,&x);
                Rec_single(OFSX,&y);
                Rec_single(OFSY,&y);
                  SBUF0=x;
                                while(TI0==0);
                                TI0=0;
                       
                                SBUF0=x;
                                while(TI0==0);
                                TI0=0;
                                        SBUF0=y;
                                while(TI0==0);
                                TI0=0;
                       
               
                                SBUF0=y;
                                while(TI0==0);
                                TI0=0;
                                SBUF0=0xcc;
                                while(TI0==0);
                                TI0=0;                */
                        Rec_double(DATAX0,&x,&x);
                        Rec_double(DATAY0,&y,&y);
                        Rec_double(DATAZ0,&z,&z);       
                        x_data=(unsigned int)x;
                        x_data<<=8;//左移8位
                        x_data+=(unsigned int )x;//加上低8位
                        x_data&=0x1fff;//清除高3位无用的
                        y_data=(unsigned int)y;
                        y_data<<=8;//左移8位
                        y_data+=(unsigned int )y;//加上低8位
                        y_data&=0x1fff;//清除高3位无用的
                        z_data=(unsigned int)z;
                        z_data<<=8;//左移8位
                        z_data+=(unsigned int )z;//加上低8位
                        z_data&=0x1fff;//清除高3位无用的

                       
                        SBUF0='X';
                        while(TI0==0);
                        TI0=0;
                        SBUF0=':';
                        while(TI0==0);
                        TI0=0;
                        uart_int(x_data);
                        SBUF0=' ';
                        while(TI0==0);
                        TI0=0;
                        SBUF0='Y';
                        while(TI0==0);
                        TI0=0;
                        SBUF0=':';
                        while(TI0==0);
                        TI0=0;
                        uart_int(y_data);
                        SBUF0=' ';
                        while(TI0==0);
                        TI0=0;
                        SBUF0='Z';
                        while(TI0==0);
                        TI0=0;
                        SBUF0=':';
                        while(TI0==0);
                        TI0=0;
                        uart_int(z_data);
                        SBUF0='\n';
                        while(TI0==0);
                        TI0=0;
                        /*        Rec_single(DATAX0,&x);
                                Rec_single(DATAX1,&x);
                                Rec_single(DATAY0,&y);
                                Rec_single(DATAY1,&y);
                                Rec_single(DATAZ0,&z);
                                Rec_single(DATAZ1,&z);

                                SBUF0=x;
                                while(TI0==0);
                                TI0=0;
                       
                                SBUF0=x;
                                while(TI0==0);
                                TI0=0;
                       
                          SBUF0=y;
                                while(TI0==0);
                                TI0=0;
                       
               
                                SBUF0=y;
                                while(TI0==0);
                                TI0=0;
                       
                                SBUF0=z;
                                while(TI0==0);
                                TI0=0;
               
                                SBUF0=z;
                                while(TI0==0);
                                TI0=0;
               
               
                                SBUF0=0xcc;        //表示结束
                                while(TI0==0);
                                TI0=0;                           */
                                //使中断清零
                                Rec_single(INT_SOURCE,&test);//通过读该寄存器使中断清零
               
}               //直到传完

void adsl_init()   
{
        Send_single(DATA_FORMAT,0x2B);      //数据通信格式;设置为自检功能禁用,4线制SPI接口,低电平中断输出,13位全分辨率,输出数据右对齐,16g量程
    Send_single(OFSX,0x00);             //X轴误差补偿; (15.6mg/LSB)
    Send_single(OFSY,0x00);             //Y轴误差补偿; (15.6mg/LSB)
    Send_single(OFSZ,0x00);             //Z轴误差补偿; (15.6mg/LSB)
    Send_single(DUR,0x00);            //敲击延时0:禁用; (1.25ms/LSB)
        Send_single(Latent,0x00);         //检测第一次敲击后的延时0:禁用; (1.25ms/LSB)
        Send_single(Window,0x00);         //敲击窗口0:禁用; (1.25ms/LSB)
    Send_single(THRESH_ACK,0x01);       //保存检测活动阀值; (62.5mg/LSB)
        Send_single(THRESH_INACT,0x01);   //保存检测静止阀值; (62.5mg/LSB)
        Send_single(TIME_INACT,0x2B);       //检测活动时间阀值; (1s/LSB)
        Send_single(THRESH_FF,0x09);      //自由落体检测推荐阀值; (62.5mg/LSB)
        Send_single(TIME_FF,0xFF);          //自由落体检测时间阀值,设置为最大时间; (5ms/LSB)
    Send_single(TAP_AXES,0x80);         //单击/双击轴控制)
    Send_single(BW_RATE,0x0a);                        //100Hz的输出数据速率
        Send_single(ACT_INACT_CTL,0x66);    //直流耦合工作模式下X,Y,Z三轴使能
        //Send_single(ACT_INACT_CTL,0x00);//轴使能控制活动和静止检测
//        Send_single(DATA_FORMAT,0X0B);               //中断高电平有效
//        Send_single(DATA_FORMAT,0X20);      //
        Send_single        (FIFO_CTL,0x86);      //FIFO的初始化
        Send_single(INT_ENABLE,0x80);       //使能数据产生中断
        Send_single(INT_MAP,0x00);          //该中断映射到INT1脚
        Send_single(POWER_CTL,0x28);      //这个一定要放在初始化的最后,都配置完了,再使能测量位要在休眠模式下配置SFR
}
void Timer_Init()
{
// Make sure the Timer can produce the appropriate frequency in 8-bit mode
// Supported SMBus Frequencies range from 10kHz to 100kHz.The CKCON register
// settings may need to change for frequencies outside this range.
#if ((SYSCLK/SMB_FREQUENCY/3) < 255)
   #define SCALE 1
      CKCON |= 0x08;                   // Timer1 clock source = SYSCLK
#elif ((SYSCLK/SMB_FREQUENCY/4/3) < 255)
   #define SCALE 4
      CKCON |= 0x01;
      CKCON &= ~0x0A;                  // Timer1 clock source = SYSCLK / 4
#endif

   TMOD = 0x20;                        // Timer1 in 8-bit auto-reload mode

   // Timer1 configured to overflow at 1/3 the rate defined by SMB_FREQUENCY
   TH1 = (unsigned char) -(SYSCLK/SMB_FREQUENCY/SCALE/3);

   TL1 = TH1;                        // Init Timer1

   TR1 = 1;                            // Timer1 enabled
}

void Timer3_Init (void)
{
   TMR3CN = 0x00;                      // Timer3 configured for 16-bit auto-
                                       // reload, low-byte interrupt disabled

   CKCON &= ~0x40;                     // Timer3 uses SYSCLK/12

   TMR3RL = (unsigned int) -(SYSCLK/12/40);// Timer3 configured to overflow after
   TMR3 = TMR3RL;                      // ~25ms (for SMBus low timeout detect):
                                       // 1/.025 = 40

   EIE1 |= 0x80;                     // Timer3 interrupt enable
   TMR3CN |= 0x04;                     // Start Timer3
}

void UART_Init()                                                //使用串口0
{
    SCON0 = 0x10;                     // SCON0: 8-bit variable bit rate
                                       //      level of STOP bit is ignored
                                       //      RX enabled
                                       //      ninth bits are zeros
                                       //      clear RI0 and TI0 bits
   #if (SYSCLK/BAUDRATE/2/256 < 1)
      TH1 = -(SYSCLK/BAUDRATE/2);
      CKCON &= ~0x0B;                  // T1M = 1; SCA1:0 = xx
      CKCON |=0x08;
   #elif (SYSCLK/BAUDRATE/2/256 < 4)
      TH1 = -(SYSCLK/BAUDRATE/2/4);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 01
      CKCON |=0x01;
   #elif (SYSCLK/BAUDRATE/2/256 < 12)
      TH1 = -(SYSCLK/BAUDRATE/2/12);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 00
   #else
      TH1 = -(SYSCLK/BAUDRATE/2/48);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 10
      CKCON |=0x02;
   #endif

   TL1 = TH1;                        // init Timer1
   TMOD &= ~0xf0;                      // TMOD: timer 1 in 8-bit autoreload
   TMOD |=0x20;
   TR1 = 1;                            // START Timer1
   TX_Ready = 1;                     // Flag showing that UART can transmit
   IP |= 0x10;                         // Make UART high priority
   ES0 = 1;                            // Enable UART0 interrupts
}

void SMBus_Init()
{
    SMB0CF = 0x5D;                      // Use Timer1 overflows as SMBus clock
                                       // source;
                                       // Disable slave mode;
                                       // Enable setup & hold time
                                       // extensions;
                                       // Enable SMBus Free timeout detect;
                                       // Enable SCL low timeout detect;

   SMB0CF |= 0x80;                     // Enable SMBus;
}

void Port_IO_Init()
{
    // P0.4-TX0 (UART0), Push-Pull,Digital
    // P0.5-RX0 (UART0), Open-Drain, Digital
    // P0.0-SDA (SMBus), Open-Drain, Digital
    // P0.1-SCL (SMBus), Push-Pull,Digital
    // P0.3-INT0 (Tmr0), Open-Drain, Digital
        TCON |= 0x00;
        XBR0      = 0x05;
        XBR1      = 0x20;
    XBR2      = 0x40;
        P0MDOUT = 0x00;                     // All P0 pins open-drain output
        IT01CF = 0x03;                      // /INT0 available at P0.3.
        P0MDOUT |= 0x10;                  // Enable UTX as push-pull output
        P0|=0xFF;//00001000
}

void Oscillator_Init()
{
   REG0CN |= 0x10;                     // Enable the precision osc. bias
   OSCICN |= 0x80;                     // Enable the precision internal osc.

//   RSTSRC = 0x06;                      // Enable missing clock detector and
                                       // leave VDD Monitor enabled.

   CLKSEL = 0x00;                      // Select precision internal osc.
                                       // divided by 1 as the system clock
}

void Interrupts_Init()
{
        IE      = 0x11;
    IP      = 0x10;
    EIE1      |= 0x01;
    EIP1      = 0x02;
        EX0=0;
        ES0=0;
        EA=1;
}

// Initialization function for device,
// Call Init_Device() from your main program
void Init_Device(void)
{

    Timer_Init();
        Timer3_Init();
    UART_Init();
    SMBus_Init();
    Port_IO_Init();
    Oscillator_Init();
    Interrupts_Init();
}
void main()
{       
//        volatile U8 dat;                  // Test counter
   U8 i;                               // Dummy variable counters
       
        PCA0MD &= ~0x40;                  // WDTE = 0 (clear watchdog timer

                            // Dummy variable counters

       while(!SDA)
   {
      // Provide clock pulses to allow the slave to advance out
      // of its current state. This will allow it to release SDA.
      XBR2 = 0x40;                     // Enable Crossbar
      SCL = 0;                         // Drive the clock low
      for(i = 0; i < 255; i++);      // Hold the clock low
      SCL = 1;                         // Release the clock
      while(!SCL);                     // Wait for open-drain
                                       // clock output to rise
      for(i = 0; i < 10; i++);         // Hold the clock high
      XBR2 = 0x00;                     // Disable Crossbar
   }
        Init_Device();
        adsl_init();//芯片初始化
//        Rec_single(DEVID,&test);        //读ID
//        P3=test;
//        Rec_single(DATA_FORMAT,&test);
//        P3=test; //可以正确读回寄存器的值
       
        EX0=1;
        while(1)
        {
                SBUF0='a';//测试串口用
        }
}
我的程序SMBUS中断大概有问题,总是不能把数据传完,SMB_BUSY总是等于1,求教高手指教,谢谢

linhui102 发表于 2013-9-1 20:48:41


         while(!SDA)
   {
      // Provide clock pulses to allow the slave to advance out
      // of its current state. This will allow it to release SDA.
      XBR2 = 0x40;                     // Enable Crossbar
      SCL = 0;                         // Drive the clock low
      for(i = 0; i < 255; i++);      // Hold the clock low
      SCL = 1;                         // Release the clock
      while(!SCL);                     // Wait for open-drain
                                       // clock output to rise
      for(i = 0; i < 10; i++);         // Hold the clock high
      XBR2 = 0x00;                     // Disable Crossbar
   }


???我不懂这段什么意思
页: [1]
查看完整版本: 贴上程序 欢迎指教