youkebing 发表于 2015-8-16 20:32:29

WIZwiki-W7500学习(2)使用SPI读取DS18B20

距离第一次测试,已经很久了,这次带来的是使用SPI读取DS18B20的温度
我们知道ds18b20需要很严格的时序,一般用纯软件的做法,当然效果不是很好,也有用串口的。我支持利用SPI,好处是,读取时不需要关中断。7500带有两个SPI口,支持DMA,FIFO。
因为这个芯片的DMA我不是很熟悉,所以就用了FIFO,为了保证连续发送,所以这个实现需要一个250us秒的定时器,当然,如果你循环周期永远不会大于380,那么在主循环中调用就可以。
直接上代码吧,写起来发现很费劲。
#include "spidrv.h"
#include "W7500x.h"
    /* < SSP_StructInit default values
       SSP_InitStructure.SSP_SerialClockRate   = 0x00;
       SSP_InitStructure.SSP_FrameFormat       = SSP_FrameFormat_MO;
       SSP_InitStructure.SSP_CPHA            = SSP_CPHA_1Edge;   
       SSP_InitStructure.SSP_CPOL            = SSP_CPOL_Low;
       SSP_InitStructure.SSP_DataSize          = SSP_DataSize_8b;
       SSP_InitStructure.SSP_SOD               = SSP_SOD_RESET;
       SSP_InitStructure.SSP_Mode            = SSP_Mode_Master;
       SSP_InitStructure.SSP_NSS               = SSP_NSS_Hard;
       SSP_InitStructure.SSP_LBM               = SSP_LBM_RESET;
       SSP_InitStructure.SSP_SSE               = SSP_SSE_SET;
       SSP_InitStructure.SSP_BaudRatePrescaler = SSP_BaudRatePrescaler_2;
    */
static u32t _fsm = 0;
static struct timer _timer;

static SSP_InitTypeDef SSP1_InitStructure;
void spi_init(void) {
    _fsm = 0;
    /* SSP0 Init -- SSP Master */
    //SSP_StructInit(&SSP0_InitStructure);
    //SSP0_InitStructure.SSP_FrameFormat= SSP_FrameFormat_MO; // Motorora SPI mode
    //SSP0_InitStructure.SSP_DataSize = SSP_DataSize_16b;
    //SSP_Init(SSP0,&SSP0_InitStructure);

    /* SSP1 Init -- SSP Slave */
    SSP_StructInit(&SSP1_InitStructure);
    SSP1_InitStructure.SSP_DataSize          = SSP_DataSize_16b;
    SSP1_InitStructure.SSP_BaudRatePrescaler = SSP_BaudRatePrescaler_254;// SSP_BaudRatePrescaler_254;
    SSP1_InitStructure.SSP_Mode            = SSP_Mode_Master;
    SSP1_InitStructure.SSP_CPOL            = SSP_CPOL_Low;//SSP_CPOL_High;
   
    SSP1_InitStructure.SSP_FrameFormat       = SSP_FrameFormat_MO;
    SSP1_InitStructure.SSP_CPHA            = SSP_CPHA_2Edge;
   
    SSP_Init(SSP0,&SSP1_InitStructure);
    //SSP0->DMACR= 0x03;
    //bsp_set_spi1_speed(SPI_SPEED_256);

    //*(u32t *)(0x41003020) = 0x32;
   

    *(u32t *)(0x4100301c) = 0x32;

}
#define ff10xffff
#define ff2ff1, ff1
#define ff3ff1, ff2
#define ff4ff1, ff3
#define ff5ff1, ff4
#define ff6ff1, ff5
#define ff7ff1, ff6
#define ff8ff1, ff7
#define ff9ff1, ff8
#define ff10ff1, ff9

#define zz10x0
#define zz2zz1, zz1
#define zz3zz1, zz2
#define zz4zz1, zz3
#define zz5zz1, zz4
#define zz6zz1, zz5
#define zz7zz1, zz6
#define zz8zz1, zz7
#define zz9zz1, zz8
#define zz10zz1, zz9
#define zz11zz1, zz10
//3.5us   
//16 ->56
//rst 500us-> 9个0x0000;
//rst wait 15-60us ->2个0xffff
//rst read 0xffffread value
// 9个0xffff;
//, 0xffff
//, 0xffff
#define WRITE10x7fff, 0xffff
#define WRITE00x0000, 0xffff

//write 1
//0x1fff, 0xffff
//write 0
//0x0000, 0x0fff
//, 0xffff, 0xffff
#define RD1    0x7fff, 0xffff
#define RD2    RD1, RD1
#define RD3    RD1, RD2
#define RD4    RD1, RD3
#define RD5    RD1, RD4
#define RD6    RD1, RD5
#define RD7    RD1, RD6
#define RD8    RD1, RD7

//read 0x7fff, 0xffff
//0x2000 & ,如果== 0,

//16
//CC

#define SKIPADDR WRITE0, WRITE0, WRITE1, WRITE1, WRITE0, WRITE0, WRITE1, WRITE1
//44
#define CONVERTWRITE0, WRITE0, WRITE1, WRITE0, WRITE0, WRITE0, WRITE1, WRITE0
//BE 1011 1110
#define RCMD   WRITE0, WRITE1, WRITE1, WRITE1, WRITE1, WRITE1, WRITE0, WRITE1
/*
#define SKIPADDR WRITE1, WRITE1, WRITE0, WRITE0, WRITE1, WRITE1, WRITE0, WRITE0
//44
#define CONVERTWRITE0, WRITE1, WRITE0, WRITE0, WRITE0, WRITE1, WRITE0, WRITE0
//BE 1011 1110
#define RCMD   WRITE1, WRITE0, WRITE1, WRITE1, WRITE1, WRITE1, WRITE1, WRITE0
*/
#define BUFLENGTH (36 + 88 + 5 + 88)

#define DSDATA1_LENGTH    (27 + 16 * 2)
#define DSDATA2_LENGTH    (27 + 16 * 2 + 16 * 9)

const u16t dsdata1 = { ff7, zz11, ff9, SKIPADDR, CONVERT};
const u16t dsdata2 = { ff7, zz11, ff9, SKIPADDR, RCMD, RD8, RD8, RD8, RD8,RD8,RD8, RD8,RD8,RD8};

#define MAXBUFLENGTH(DSDATA1_LENGTH + DSDATA2_LENGTH + DSDATA3_LENGTH + DSDATA4_LENGTH)
#define DATA_OFFSET    (DSDATA1_LENGTH + DSDATA2_LENGTH)
static u8t _rbuf;
static s32t index, rindex;


//CRC = X8 + X5 + X4 + 1
const u8t Crc8Table ={
0,94, 188,226,97,63,221,131,194,156,126,32,163,253,31,65,
157,195,33,127,252,162,64,30,95,1,227,189,62,96,130,220,
35,125,159,193,66,28,254,160,225,191,93,3,128,222,60,98,
190,224,2,92,223,129,99,61,124,34,192,158,29,67,161,255,
70,24,250,164,39,121,155,197,132,218,56,102,229,187,89,7,
219,133, 103,57,186,228,6,88,25,71,165,251,120,38,196,154,
101,59, 217,135,4,90,184,230,167,249,27,69,198,152,122,36,
248,166, 68,26,153,199,37,123,58,100,134,216,91,5,231,185,
140,210, 48,110,237,179,81,15,78,16,242,172,47,113,147,205,
17,79,173,243,112,46,204,146,211,141,111,49,178,236,14,80,
175,241, 19,77,206,144,114,44,109,51,209,143,12,82,176,238,
50,108,142,208,83,13,239,177,240,174,76,18,145,207,45,115,
202,148, 118,40,171,245,23,73,8,86,180,234,105,55,213, 139,
87,9,235,181,54,104,138,212,149,203,41,119,244,170,72,22,
233,183,85,11,136,214,52,106,43,117,151,201,74,20,246,168,
116,42,200,150,21,75,169,247,182,232,10,84,215,137,107,53};

u8t GetCRC(u8t *str, u32t length) {
    u8t crc_data=0;
    u32t i;
    for(i=0;i<length;i++) {//查表校验
      crc_data = Crc8Table];
    }
    return (crc_data);
}

void spi_recive(void) {
    s32t t, r, i;
    while(SSP_GetFlagStatus(SSP0, SSP_FLAG_RNE) == SET) {
      t = (u16t)SSP_ReceiveData(SSP0);
      if ((rindex >= 0) && ((rindex & 0x01) == 0)) {
            t &= 0x0f00;
            i = rindex / 16;
            r = _rbuf;
            r >>= 1;
            r &= 0x7f;
            if (t == 0x0f00) {
                r |= 0x80;
            }
            _rbuf = r;
      }
      rindex++;
    }
}
s32t wd;
void spi_process(void) {
    u8t temp;
    u8t TL,TH;
    s32t tem;

    TL = _rbuf; // LSB   
    TH = _rbuf; // MSB   
      
    if(TH>7) {
      TH=~TH;
      TL=~TL;
      temp=0;//温度为负
    }
    else {
      temp=1;//温度为正         
    }
    tem=TH<<8 | TL; //获得不带符号位的11位温度值
    //转换 *0.625
    tem = tem*10000;
    tem = tem>>4;
    if(temp) {
      wd = tem;
    }
    else{
      wd = -tem;
    }
}

s32t spi_temperature(void){
    return wd;
}
#define FSM_INIT             0
#define FSM_READY            1
#define FSM_WAITFREE         2
#define FSM_SEND_DATA1       3
#define FSM_WAIT_DATA1_OK    4
#define FSM_SEND_DATA2       5
#define FSM_WAIT_DATA2_OK    6
#define FSM_WAIT_CONVERT   7

void spi_timerpoll(void) {
    if (_fsm == FSM_SEND_DATA1) {
      while((SSP_GetFlagStatus(SSP0, SSP_FLAG_TNF) == SET) && index < DSDATA1_LENGTH) {
            SSP_SendData(SSP0, dsdata1);
      }
      if(index >= (DSDATA1_LENGTH)) {
            timer_init(&_timer);
            _fsm = FSM_WAIT_DATA1_OK;
      }
    }
    else if (_fsm == FSM_SEND_DATA2) {
      spi_recive();
      while((SSP_GetFlagStatus(SSP0, SSP_FLAG_TNF) == SET) && index < DSDATA2_LENGTH) {
            SSP_SendData(SSP0, dsdata2);
      }
      spi_recive();
      if(index >= DSDATA2_LENGTH) {
            _fsm = FSM_WAIT_DATA2_OK;
      }
    }
}
void spi_service(void) {
    u32t temp_interrupt;

    temp_interrupt = (NVIC->ISPR);
    (NVIC->ISPR) = (u32t)0xFFFFFFFF;

    if ((_fsm == FSM_SEND_DATA1) || (_fsm == FSM_SEND_DATA2)) {
      (NVIC->ISPR) = temp_interrupt;
      return;
    }

    (NVIC->ISPR) = temp_interrupt;
    //CTX_EXIT();

    if (_fsm == FSM_READY) {
      if (timer_expired(&_timer, 9000)) {
            while(SSP_GetFlagStatus(SSP0, SSP_FLAG_RNE) == SET) {
                SSP_ReceiveData(SSP0);
            }
            printf("\r\nGetting Started\r\n");
            index = 0;
            _fsm = FSM_SEND_DATA1;
      }
    }
    else if(_fsm == FSM_WAIT_DATA1_OK) {
      if (timer_expired(&_timer, 1000)) {
            while(SSP_GetFlagStatus(SSP0, SSP_FLAG_RNE) == SET) {
                SSP_ReceiveData(SSP0);
            }
            index = 0;
            rindex = 16 * 9 - DSDATA2_LENGTH;
            _fsm = FSM_SEND_DATA2;
      }
    }
    else if(_fsm == FSM_WAIT_DATA2_OK) {
      spi_recive();
      if (SSP_GetFlagStatus(SSP0, SSP_FLAG_BSY)) {
            return;
      }
      spi_recive();
      /*
      t = _rbuf;
      t <<= 4;
      printf("SET __%d__%d\r\n", index, rindex);
      rindex /= 16;
      for(i = 0; i < rindex; i++){
            printf("%04X ", _rbuf);
      }
      printf("\r\nSET END \r\n");*/
      if (GetCRC(_rbuf, 8) == _rbuf) {
            spi_process();
            printf("Measuring success:%03d.%04d\r\n", wd / 10000, wd %10000);
            //printf("\r\nwd crc ok {%08d} \r\n", wd);
      }
      else {
            printf("Measurement fails\r\n");
      }
      _fsm = FSM_INIT;
    }
    else {
      timer_init(&_timer);
      _fsm = FSM_READY;
    }
}

youkebing 发表于 2015-8-16 20:34:32

其中spi_timerpoll必须保证在380us内调用一次(我测试时放在一个250us的定时器里调用),spi_service放在主循环中调用

liudan 发表于 2015-8-20 10:45:36

W7500可以买到了?

youkebing 发表于 2015-8-20 10:57:18

liudan 发表于 2015-8-20 10:45
W7500可以买到了?

上次问了下,说可能比stm32f107便宜一点点

youkebing 发表于 2015-8-20 10:57:51

liudan 发表于 2015-8-20 10:45
W7500可以买到了?

我这个是在评估板上进行的测试
页: [1]
查看完整版本: WIZwiki-W7500学习(2)使用SPI读取DS18B20