[讨论] C8051的SMBUS问题,求助

caobingluo   2011-10-3 15:29 楼主


#include #include // SFR declarations #include "adxl.h" //----------------------------------------------------------------------------- // Global CONSTANTS //----------------------------------------------------------------------------- #define SYSCLK 24500000 // System clock frequency in Hz #define SMB_FREQUENCY 10000 // Target SCL clock rate // This example supports between 10kHz // and 100kHz #define BAUDRATE 9600 // Baud rate of UART in bps #define WRITE 0x00 // SMBus WRITE command #define READ 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) #define SLAVE_ADDR 0xA6 // Device address for slave target // Status vector - top 4 bits only #define SMB_MTSTA 0xE0 // (MT) start transmitted #define SMB_MTDB 0xC0 // (MT) data byte transmitted #define SMB_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[2],y[2],z[2];//分别存储传过来的 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 // - All outgoing data is read from global variable // //----------------------------------------------------------------------------- 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[0],&x[1]); Rec_single(OFSX,&y[0]); Rec_single(OFSY,&y[1]); SBUF0=x[1]; while(TI0==0); TI0=0; SBUF0=x[0]; while(TI0==0); TI0=0; SBUF0=y[1]; while(TI0==0); TI0=0; SBUF0=y[0]; while(TI0==0); TI0=0; SBUF0=0xcc; while(TI0==0); TI0=0; */ Rec_double(DATAX0,&x[0],&x[1]); Rec_double(DATAY0,&y[0],&y[1]); Rec_double(DATAZ0,&z[0],&z[1]); x_data=(unsigned int)x[1]; x_data<<=8;//左移8位 x_data+=(unsigned int )x[0];//加上低8位 x_data&=0x1fff;//清除高3位无用的 y_data=(unsigned int)y[1]; y_data<<=8;//左移8位 y_data+=(unsigned int )y[0];//加上低8位 y_data&=0x1fff;//清除高3位无用的 z_data=(unsigned int)z[1]; z_data<<=8;//左移8位 z_data+=(unsigned int )z[0];//加上低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[0]); Rec_single(DATAX1,&x[1]); Rec_single(DATAY0,&y[0]); Rec_single(DATAY1,&y[1]); Rec_single(DATAZ0,&z[0]); Rec_single(DATAZ1,&z[1]); SBUF0=x[1]; while(TI0==0); TI0=0; SBUF0=x[0]; while(TI0==0); TI0=0; SBUF0=y[1]; while(TI0==0); TI0=0; SBUF0=y[0]; while(TI0==0); TI0=0; SBUF0=z[1]; while(TI0==0); TI0=0; SBUF0=z[0]; 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中端子程序里面有什么错误还是哪个标志位有问题,我是拿020的程序和996的SMBUS例程改的,但是总是SMBUS等于1,导致一直死在注表情的那行while(SMB_BUSY);里,我接的是ADXL345,MCU是C8051F996。求助

 

本帖最后由 paulhyde 于 2014-9-15 03:46 编辑

回复评论 (1)



头文件没复制好,如下:

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

 


 

 

本帖最后由 paulhyde 于 2014-9-15 03:46 编辑
点赞  2011-10-3 15:34
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复