Feedback on http://www.maxim-ic.com/appnotes.cfm?an_pk=1784

Member Comments  
  learner   - some problem (no rating)
2008-12-08
Dear engineer of Maxim:
I am a student from University of science and technology of China.
I participate in one project which use Max6651 to control multiple fans.
But I can't exactly programme to control this chip.One simple piece of code can work(shown below)
------------------------------------------
#include <c8051f020.h>
#include <intrins.h>
#define write 0x00//SMBus写允许
#define read  0x01//SMBus读允许
#define fan_controler_1 0x90//MAX6651的ADD接GND
#define fan_controler_2 0x96//MAX6651的ADD(P8)接VCC
#define smb_bus_error 0x00//总线错误
#define smb_start 0x08//起始条件已发送
#define smb_restart 0x10//重复起始条件
#define smb_mt_add_ack 0x18//主发送器:从地址   WRITE已发送,收到ACK
#define smb_mt_add_nack 0x20//主发送器:从地址   WRITE已发送,收到NACK
#define smb_mt_data_ack 0x28//主发送器:数据字节已发送,收到ACK
#define smb_mt_data_nack 0x30//主发送器:数据字节已发送,收到NACK
#define smb_mt_compete_lost 0x38//主发送器:竞争失败
#define smb_mr_add_ack 0x40//主接收器:从地址   READ 已发送。收到ACK
#define smb_mr_add_nack 0x48//主接收器:从地址   READ 已发送。收到NACK
#define smb_mr_data_ack 0x50//收到数据字节,ACK已发送
#define smb_mr_data_nack 0x58//收到数据字节。NACK已发送
unsigned char command;// 在SMBus中断服务程序中用于保存从地址   R/W 位
unsigned char register_address;//一个字节,寄存器地址
unsigned char word;//一个字节的数据
unsigned char fan_speed_check[3];//用于获得风扇的转速
sbit RUN_LED = P3^4;
sbit ERR_LED = P3^5;
bit frame=0;//用于表示数据是第几帧
bit sm_busy;// 该位在发送或接收开始时被置1,操作结束后由中断服务程序清0
void sm_interrupt(void);
void sm_send(unsigned char chip_select,unsigned char byte_register_address,unsigned char out_byte);
unsigned char sm_receive(unsigned char chip_select,unsigned char byte_register_address);
// Peripheral specific initialization functions,
// Called from the Init_Device() function
void Reset_Sources_Init()
{
    WDTCN     = 0xDE;//看门狗禁止
    WDTCN     = 0xAD;
}
void Timer_Init()
{
    TMR3CN    = 0x04;//启动T3
    TMR3RLL   = 0xCA;
    TMR3RLH   = 0x7D;
    TMR3L     = 0xCA;
    TMR3H     = 0x7D;
}
void SMBus_Init()
{
    SMB0CN    = 0x43;//SMBUS允许 SCL超时检测
    SMB0CR    = 0x66;//50kb内部晶振
}

void Port_IO_Init()
{
    // P0.0  -  TX0 (UART0), Open-Drain, Digital
    // P0.1  -  RX0 (UART0), Open-Drain, Digital
    // P0.2  -  SDA (SMBus), Open-Drain, Digital
    // P0.3  -  SCL (SMBus), Open-Drain, Digital
    XBR0      = 0x05;
    XBR2      = 0x40;//交叉开关允许
     P3MDOUT   = 0x30;//设置P3.4和P3.5为推挽模式
}

void Oscillator_Init()
{
    OSCICN    = 0x07;//内部晶振作为时钟源,并设为16MHz
}

void Interrupts_Init()
{
    IE        = 0x80;//全局中断开启
    EIE1      = 0x02;//SMBUS中断开启
    EIE2      = 0x01;//开T3中断
    EIP1      = 0x02;
    EIP2      = 0x01;
}

// Initialization function for device,
// Call Init_Device() from your main program
void Init_Device(void)
{
    Reset_Sources_Init();
    SMBus_Init();
    Port_IO_Init();
    Oscillator_Init();
    Interrupts_Init();
}

void delay1us(unsigned char t)
{
while(t)
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
t--;
}
}
void delay1ms(unsigned char t)
{
while(t)
{
delay1us(200);
delay1us(200);
delay1us(200);
delay1us(200);
delay1us(200);
t--;
}
}
void delay1s(unsigned char t)
{
while(t)
{
delay1ms(200);
delay1ms(200);
delay1ms(200);
delay1ms(200);
delay1ms(200);
t--;
}
}
void GetBus()
{
SMB0CN=0x47;//SMBUS允许 超时检测 应答允许
STA=1;
while(SI==0);
}

void main(void)
{
int i;

Init_Device();

EA=1;// 全局中断允许

sm_busy=0;

RUN_LED=1;//测试灯亮
         ERR_LED=1;

    sm_send(fan_controler_2,0x02,0x2c);//配置config寄存器,闭环,12V,SCALE=16
for(i=3;i>0;i--)
{
delay1s(1);
}
sm_send(fan_controler_2,0x00,0xf8);//一半速度3830rpm
for(i=3;i>0;i--)
{
delay1s(1);
}
sm_send(fan_controler_2,0x04,0x2e);//配置GPIO寄存器
for(i=3;i>0;i--)
{
delay1s(1);
}
sm_send(fan_controler_2,0x16,0x00);//配置count time
for(i=3;i>0;i--)
{
delay1s(1);
}
//sm_send(fan_controler_2,0x00,0xf8);//相对明显的慢速
//sm_send(fan_controler_2,0x08,0x02);//配置alarm寄存器,设置最小值报警
while(1)
{
RUN_LED=0;//测试灯灭
                  ERR_LED=0;

fan_speed_check[0]=sm_receive(fan_controler_2,0x0c);
delay1s(1);
fan_speed_check[1]=sm_receive(fan_controler_2,0x0e);
delay1s(1);
fan_speed_check[2]=sm_receive(fan_controler_2,0x10);
delay1s(1);
        if(fan_speed_check[0]<25||fan_speed_check[1]<25||fan_speed_check[2]<25)
{
//sm_send(fan_controler_2,0x00,0x1f);//全速运行
            sm_send(fan_controler_2,0x02,0x1c);//全停
for(i=4;i>0;i--)
{
            RUN_LED=1;//测试灯亮
                ERR_LED=1;
delay1s(1);
}
}
}
}

void sm_send (unsigned char chip_select, unsigned char byte_register_address, unsigned char out_byte)
{
while (sm_busy); // 等待SMBus空闲
sm_busy = 1; // 占用SMBus(设置为忙)
command = (chip_select | write); // 片选   WRITE
register_address = byte_register_address; // 寄存器地址
word = out_byte; // 待写数据
GetBus();
    Timer_Init();//允许T3保证通讯不超时
while(sm_busy);
TMR3CN &=0x82;//禁止T3
}
unsigned char sm_receive (unsigned char chip_select, unsigned char byte_register_address)
{
while (sm_busy); // 等待总线空闲
sm_busy = 1; //占用SMBus(设置为忙)
command = (chip_select | read); // 片选  READ
register_address = byte_register_address;             // 高8 位地址
GetBus();
Timer_Init(); //允许T3保证通讯不超时
while (sm_busy); // 等待传输结束
TMR3CN &=0x82;                      //禁止T3
return word;
}
void sm_interrupt (void) interrupt 7
{
switch (SMB0STA)// SMBus状态码(SMB0STA寄存器)
{ // 主发送器/接收器:起始条件已发送
     // 在该状态发送的COMMAND字的R/W位总是为0(W),
     // 因为对于读和写操作来说都必须先写寄存器地址。
case smb_start:
SMB0DAT = (command & 0xfe); // 装入要访问的从器件的地址
STA = 0; // 手动清除START位
break;
//主发送器/接收器:重复起始条件已发送。
// 该状态只应在读操作期间出现,在从地址已发送并得到确认之后
case smb_restart:
SMB0DAT = command; // COMMAND中应保持从地址   R
STA = 0;
break;
// 主发送器:从地址   WRITE已发送,收到ACK。
case smb_mt_add_ack:
SMB0DAT = register_address; // 装入待写寄存器地址
break;
            // 主发送器:从地址   WRITE已发送,收到NACK。
            // 从器件不应答,发送STOP   START重试
case smb_mt_add_nack:
STO = 1;
STA = 1;
sm_busy=0;
break;
// 主发送器:数据字节已发送,收到ACK。
// 该状态在写和读操作中都要用到。检查COMMAND
// 中的R/W 值以决定下一状态。
case smb_mt_data_ack:
if (command & 0x01) // 如果R/W=READ,发送重复起始条件
STA = 1;
else if(frame==1)// 如果R/W=WRITE,装入待写字节
{//一次对MAX6651的完整写操作完成,frame归零,为下一次传输做准备
frame=0;
STO=1;
sm_busy=0;
ENSMB=0;
ENSMB=1;//复位SMBUS
}
else
{//传输尚未完成,将数据写入寄存器
frame=1;
SMB0DAT = word;
}
break;
// 主发送器:数据字节已发送,收到NACK。
// 从器件不应答,发送STOP   START重试
case smb_mt_data_nack:
STO = 1;
STA = 1;
break;
// 主发送器:竞争失败
// 不应出现。如果出现,重新开始传输过程
case smb_mt_compete_lost:
STO = 1;
STA = 1;
break;
// 主接收器:从地址   READ 已发送。收到ACK。
// 设置为在下一次传输后发送NACK,因为那将是最后一个字节(唯一)。
case smb_mr_add_ack:
AA = 0; // 在应答周期NACK。
break;
// 主接收器:从地址   READ 已发送。收到NACK。
// 从器件不应答,发送重复起始条件重试
case smb_mr_add_nack:
STA = 1;
break;
// 收到数据字节。ACK已发送。
// 该状态不应出现,因为AA已在前一状态被清0。如果出现,发送停止条件。
     case smb_mr_data_ack:
STO = 1;
sm_busy = 0;
break;
// 收到数据字节。NACK已发送。
    // 读操作已完成。读数据寄存器后发送停止条件。
case smb_mr_data_nack:
word = SMB0DAT;
STO = 1;
sm_busy = 0; // 释放SMBus
break;
// 在本应用中,所有其它状态码没有意义。通信复位。
default:
STO = 1; // 通信复位。
sm_busy = 0;
break;
}
SI=0; // 清除中断标志
}
void timer3_interrupt (void) interrupt 14
{
sm_busy=0;
ENSMB=0;
ENSMB=1;
}
------------------------------------------------------
but when I try to add more action,for example,add the function call:"sm_send(fan_controler_2,0x08,0x02);"it turn out to be wrong.(May be I have a misunderstanding of SMBus)And when I try to get the speed of fans and show them on the PC screen through the uart way,I got nothing,and the fans stop once I read the tach1,tach2 and tach3 register.(according
to the data sheet "Fan-speed Regulators and Monitors with SMBus/I2C-Compatible Interface",I still don't know the relationship between the value red from tach1,tach2,tach3 register and the real speed of fans)
The fan we use is "AVC,DB04028B12L",and the MCU is C8051F020.
I can't explain it clearly here so if you will,please download the material from the website:http://home.ustc.edu.cn/~vllm(just click the title"工程问题请教")
I wish that you can offer some actual code that control the Max6651 fine.
If so,could you send it to my mailbox:vllm@mail.ustc.edu.cn
Thank you very much!
  Moe   - Re: some problem (no rating)
2008-12-09
Not sure anyone will be able to help you debug your code, but I am forwarding it to tech support to see if they have any suggestions.
  learner   - Re: Re: some problem (no rating)
2008-12-09
Thanks a lot!
Your Comments
Login or register to post a comment.