1-Wire的使用

代码:

ds18b20.c

/*
  《AVR专题精选》随书例程
  
  3.通信接口使用技巧

  项目:1-Wire 单总线的使用
  文件:ds1820.c
  说明:DS18B20驱动文件。
        为了简单,没有读取芯片地址,也没有计算校验
        
  作者:邵子扬
  时间:2012年12月13日

*/
#include "owi.h"
#include "DS1820.h"

/*! \brief  Read the temperature from a DS1820 temperature sensor.
 *
 *  This function will start a conversion and read back the temperature
 *  from a DS1820 temperature sensor.
 *
 *  \param  bus A bitmask of the bus where the DS1820 is located.
 *  
 *  \param  id  The 64 bit identifier of the DS1820.
 *
 *  \return The 16 bit signed temperature read from the DS1820.
 */
 
/*
signed int DS1820_ReadTemperature(unsigned char bus, unsigned char * id)
{
  signed int temperature;
    
  // Reset, presence.
  if (!OWI_DetectPresence(bus))
  {
    return DS1820_ERROR; // Error
  }
  // Match the id found earlier.
  OWI_MatchRom(id, bus);
  // Send start conversion command.
  OWI_SendByte(DS1820_START_CONVERSION, bus);
  // Wait until conversion is finished.
  // Bus line is held low until conversion is finished.
  while (!OWI_ReadBit(bus))
  {
    
  }
  // Reset, presence.
  if(!OWI_DetectPresence(bus))
  {
    return DS1820_ERROR; // Error
  }
  // Match id again.
  OWI_MatchRom(id, bus);
  // Send READ SCRATCHPAD command.
  OWI_SendByte(DS1820_READ_SCRATCHPAD, bus);
  // Read only two first bytes (temperature low, temperature high)
  // and place them in the 16 bit temperature variable.
  temperature = OWI_ReceiveByte(bus);
  temperature |= (OWI_ReceiveByte(bus) << 8);
    
  return temperature;
}
*/

// 读取温度的简单函数,忽略了ROM识别,适合总线上只有1个 DS1820
// 的应用情况。
signed int DS1820_SimpleReadTemperature(unsigned char pin)
{
  signed int temperature;

  OWI_DetectPresence(pin);
  OWI_SkipRom(pin);
  OWI_SendByte(DS1820_START_CONVERSION, pin);

  OWI_DetectPresence(pin);
  OWI_SkipRom(pin);
  OWI_SendByte(DS1820_READ_SCRATCHPAD, pin);

  temperature = OWI_ReceiveByte(pin);
  temperature |= (OWI_ReceiveByte(pin) << 8);

  return temperature/16;
}

ds2413.c

/*
  《AVR专题精选》随书例程
  
  3.通信接口使用技巧

  项目:1-Wire 单总线的使用
  文件:ds2413.c
  说明:DS2413驱动文件。
        为了简单,没有读取芯片地址,也没有计算校验
        
  作者:邵子扬
  时间:2012年12月13日

*/
#include "owi.h"
#include "DS2413.h"

// 读取DS2413状态
// pin: IO引脚序号
//      端口需要在cfg.h中预先指定
unsigned char DS2413_SimpleRead(unsigned char pin)
{
  unsigned char PIO;

  // 检测设备
  OWI_DetectPresence(pin);
  // 忽略ROM地址
  OWI_SkipRom(pin);

  // 发送读取命令
  OWI_SendByte(DS2413_PIO_Access_Read, pin);
  OWI_ReceiveByte(pin);
  OWI_ReceiveByte(pin);
  // 读取数据
  PIO = OWI_ReceiveByte(pin);

  OWI_DetectPresence(pin);

  return PIO;
}

// 写入数据到 DS2413
// dat: 需要些入的数据
// pin: IO端口序号
unsigned char DS2413_SimpleWrite(unsigned char dat, unsigned char pin)
{
  unsigned char PIO;

  // 检测芯片
  if(!OWI_DetectPresence(pin))
    return DS2413_ERROR;
  
  // 忽略地址
  OWI_SkipRom(pin);

  // 发送写入命令
  OWI_SendByte(DS2413_PIO_Access_Write, pin);
  // 发送数据
  OWI_SendByte(dat, pin);
  // 发送数据补码
  OWI_SendByte(~dat, pin);
  OWI_ReceiveByte(pin);
  // 读取数据
  PIO = OWI_ReceiveByte(pin);

  if(!OWI_DetectPresence(pin))
    return DS2413_ERROR;


  return PIO;
}

lcd.c

/*
  《AVR专题精选》随书例程
  
  3.通信接口使用技巧

  项目:1-Wire 单总线的使用
  文件:lcd.c
  说明:16x1字符型液晶驱动文件
        
  作者:邵子扬
  时间:2012年12月13日

*/
#include <avr/io.h>
#include "macromcu.h"

#include "cfg.h"

#include <util/delay.h>

#define LCDDDR        MACRO_CONCAT2(DDR, LCD_PORT)
#define LCDDATA_IN    MACRO_CONCAT2(PIN, LCD_PORT)
#define LCDDATA_OUT   MACRO_CONCAT2(PORT,LCD_PORT)

// 向液晶控制器发送命令
void lcd_write(unsigned char RS, unsigned char dat)
{
  // 等待液晶内部操作完成
  // 使用延时法,没有读取标志位
  _delay_us(50);

  PINOUT(LCD_RS, RS);
  LCDDATA_OUT = dat;
  PINSET(LCD_E);
  PINCLR(LCD_E);
}

// 液晶初始化
void lcd_init()
{
  LCDDDR = 0xFF;

  PINDIR(LCD_E,  PIN_OUTPUT);
  PINDIR(LCD_RW, PIN_OUTPUT);
  PINDIR(LCD_RS, PIN_OUTPUT);

  PINCLR(LCD_E);
  PINCLR(LCD_RW);

  _delay_ms(5);
  lcd_write(0, 0x30);
  lcd_write(0, 0x01);
  _delay_ms(2);
  lcd_write(0, 0x06);
  lcd_write(0, 0x0C);
}

// 在指定位置显示字符
void lcd_chr(unsigned char x, unsigned char dat)
{
  lcd_write(0, 0x80 + x); // 设置地址
  lcd_write(1, dat);      // 写入字符数据
}

// HEX数据转换为字符
unsigned char HexToChr(unsigned char dat)
{
  if(dat > 15)
    return '0';
  if(dat >9)
    return dat - 10 + 'A';
  return dat + '0'; 
}

// 显示HEX数据
void lcd_hex(unsigned char x, unsigned char dat)
{
  lcd_chr(x, HexToChr(dat/16));
  lcd_chr(x+1, HexToChr(dat%16));
}

// 显示字符串
void lcd_str(unsigned char x, char *s)
{
  while(*s)
  {
    lcd_chr(x, *s);
    x++;
    s++;
  }
}

main.c

/*
  《AVR专题精选》随书例程
  
  3.通信接口使用技巧

  项目:1-Wire 单总线的使用
  文件:main.c
  说明:主程序文件。
        演示了温度传感器DS18B20和双通道开关DS2413的基本用法
        
  作者:邵子扬
  时间:2012年12月13日

*/
#include <avr/io.h>

#include "cfg.h"
#include "macromcu.h"
#include "lcd.h"

#include "owi.h"
#include "ds1820.h"
#include "ds2413.h"

#include <util/delay.h>

unsigned char cnt=0;
volatile unsigned char stat;
volatile signed int temperature;
char s[10];

// 初始化
void init()
{
  lcd_init();   // 液晶显示器初始化
}

int main()
{

  init();

  // 向DS2413写入数据0xFF
  DS2413_SimpleWrite(0xFF, OWI_PIN1);

  while(1)
  {
    _delay_ms(1000);  // 延时1秒
    cnt++;            // 计数器累加
    lcd_hex(0, cnt);  // 显示

    // 通过DS18B20读取温度
    temperature = DS1820_SimpleReadTemperature(OWI_PIN2);
    
    // 将结果转换为字符串
    // 判断符号位
    if(temperature < 0)
    {
      s[0] = '-';
      temperature = -temperature;
    }
    else
      s[0] = '+';
    s[1] = temperature/100 + '0';
    temperature = temperature % 100;
    s[2] = temperature/10 + '0';
    s[3] = temperature%10 + '0';
    s[4] = 0;
    
    // 显示温度
    lcd_str(5, s);

    // 读取DS2413状态
    stat = DS2413_SimpleRead(OWI_PIN1);
    if(stat & 0x04)
      stat = 0xFF;
    else
      stat = 0xFE;
    
    // 根据按键状态更新LED
    stat = DS213_SimpleWrite(stat, OWI_PIN1);    

    // 更新显示
    lcd_hex(14, stat);
  }

  return 0;
}

owi.c

/*
  《AVR专题精选》随书例程
  
  3.通信接口使用技巧

  项目:1-Wire 单总线的使用
  文件:owi.c
  说明:1-Wire驱动文件。
        从AVR318例程移植而来,并做了一定优化
        
  作者:邵子扬
  时间:2012年12月13日

*/
#include "owi.h"

// Port configuration registers for 1-Wire buses.

//!< 1-Wire PORT Data register.
#define OWIPORT     MACRO_CONCAT2(PORT, OWI_PORT)
//!< 1-Wire Input pin register.
#define OWIPIN      MACRO_CONCAT2(PIN,  OWI_PORT)
//!< 1-Wire Data direction register.
#define OWIDDR      MACRO_CONCAT2(DDR,  OWI_PORT)


/*! \brief  Compute the CRC8 value of a data set.
 *
 *  This function will compute the CRC8 or DOW-CRC of inData using seed
 *  as inital value for the CRC.
 *
 *  \param  inData  One byte of data to compute CRC from.
 *
 *  \param  seed    The starting value of the CRC.
 *
 *  \return The CRC8 of inData with seed as initial value.
 *
 *  \note   Setting seed to 0 computes the crc8 of the inData.
 *
 *  \note   Constantly passing the return value of this function 
 *          As the seed argument computes the CRC8 value of a
 *          longer string of data.
 */
unsigned char OWI_CRC8(unsigned char inData, unsigned char seed)
{
  unsigned char bitsLeft;
  unsigned char temp;

  for (bitsLeft = 8; bitsLeft > 0; bitsLeft--)
  {
    temp = ((seed ^ inData) & 0x01);
    if (temp == 0)
    {
      seed >>= 1;
    }
    else
    {
      seed ^= 0x18;
      seed >>= 1;
      seed |= 0x80;
    }
    inData >>= 1;
  }
  return seed;    
}

/*! \brief  Calculate and check the CRC of a 64 bit ROM identifier.
 *  
 *  This function computes the CRC8 value of the first 56 bits of a
 *  64 bit identifier. It then checks the calculated value against the
 *  CRC value stored in ROM.
 *
 *  \param  romvalue    A pointer to an array holding a 64 bit identifier.
 *
 *  \retval OWI_CRC_OK      The CRC's matched.
 *  \retval OWI_CRC_ERROR   There was a discrepancy between the calculated and the stored CRC.
 */
unsigned char OWI_CheckRomCRC(unsigned char * romValue)
{
  unsigned char i;
  unsigned char crc8 = 0;
    
  for (i = 0; i < 7; i++)
  {
    crc8 = OWI_CRC8(*romValue, crc8);
    romValue++;
  }
  if (crc8 == (*romValue))
  {
    return OWI_CRC_OK;
  }
  return OWI_CRC_ERROR;
}

/*! \brief Initialization of the one wire bus(es). (Software only driver)
 *  
 *  This function initializes the 1-Wire bus(es) by releasing it and
 *  waiting until any presence sinals are finished.
 *
 *  \param  pins    A bitmask of the buses to initialize.
 */
void OWI_Init(unsigned char pins)
{
  OWI_RELEASE_BUS(pins);
  // The first rising edge can be interpreted by a slave as the end of a
  // Reset pulse. Delay for the required reset recovery time (H) to be 
  // sure that the real reset is interpreted correctly.
  _delay_us(OWI_DELAY_H_STD_MODE);
}

/*! \brief  Write a '1' bit to the bus(es). (Software only driver)
 *
 *  Generates the waveform for transmission of a '1' bit on the 1-Wire
 *  bus.
 *
 *  \param  pins    A bitmask of the buses to write to.
 */
void OWI_WriteBit1(unsigned char pins)
{
  unsigned char intState;
    
  // Disable interrupts.
  intState = __save_interrupt();
  cli();
    
  // Drive bus low and delay.
  OWI_PULL_BUS_LOW(pins);
  _delay_us(OWI_DELAY_A_STD_MODE);
    
  // Release bus and delay.
  OWI_RELEASE_BUS(pins);
  _delay_us(OWI_DELAY_B_STD_MODE);
    
  // Restore interrupts.
  __restore_interrupt(intState);
}


/*! \brief  Write a '0' to the bus(es). (Software only driver)
 *
 *  Generates the waveform for transmission of a '0' bit on the 1-Wire(R)
 *  bus.
 *
 *  \param  pins    A bitmask of the buses to write to.
 */
void OWI_WriteBit0(unsigned char pins)
{
  unsigned char intState;
    
  // Disable interrupts.
  intState = __save_interrupt();
  cli();
    
  // Drive bus low and delay.
  OWI_PULL_BUS_LOW(pins);
  _delay_us(OWI_DELAY_C_STD_MODE);
    
  // Release bus and delay.
  OWI_RELEASE_BUS(pins);
  _delay_us(OWI_DELAY_D_STD_MODE);
    
  // Restore interrupts.
  __restore_interrupt(intState);
}


/*! \brief  Read a bit from the bus(es). (Software only driver)
 *
 *  Generates the waveform for reception of a bit on the 1-Wire(R) bus(es).
 *
 *  \param  pins    A bitmask of the bus(es) to read from.
 *
 *  \return A bitmask of the buses where a '1' was read.
 */
unsigned char OWI_ReadBit(unsigned char pins)
{
  unsigned char intState;
  unsigned char bitsRead;
    
  // Disable interrupts.
  intState = __save_interrupt();
  cli();
    
  // Drive bus low and delay.
  OWI_PULL_BUS_LOW(pins);
  _delay_us(OWI_DELAY_A_STD_MODE);
    
  // Release bus and delay.
  OWI_RELEASE_BUS(pins);
  _delay_us(OWI_DELAY_E_STD_MODE);
    
  // Sample bus and delay.
  bitsRead = OWIPIN & (1 << pins);
  _delay_us(OWI_DELAY_F_STD_MODE);
    
  // Restore interrupts.
  __restore_interrupt(intState);
    
  return bitsRead;
}

/*! \brief  Send a Reset signal and listen for Presence signal. (software
 *  only driver)
 *
 *  Generates the waveform for transmission of a Reset pulse on the 
 *  1-Wire(R) bus and listens for presence signals.
 *
 *  \param  pins    A bitmask of the buses to send the Reset signal on.
 *
 *  \return A bitmask of the buses where a presence signal was detected.
 */
unsigned char OWI_DetectPresence(unsigned char pins)
{
  unsigned char intState;
  unsigned char presenceDetected;
    
  // Disable interrupts.
  intState = __save_interrupt();
  cli();
    
  // Drive bus low and delay.
  OWI_PULL_BUS_LOW(pins);
  _delay_us(OWI_DELAY_H_STD_MODE);
    
  // Release bus and delay.
  OWI_RELEASE_BUS(pins);
  _delay_us(OWI_DELAY_I_STD_MODE);
    
  // Sample bus to detect presence signal and delay.
  presenceDetected = ((~OWIPIN) & (1 << pins));
  _delay_us(OWI_DELAY_J_STD_MODE);
    
  // Restore interrupts.
  __restore_interrupt(intState);
    
  return presenceDetected;
}

/*! \brief  Sends one byte of data on the 1-Wire(R) bus(es).
 *  
 *  This function automates the task of sending a complete byte
 *  of data on the 1-Wire bus(es).
 *
 *  \param  data    The data to send on the bus(es).
 *  
 *  \param  pins    A bitmask of the buses to send the data to.
 */
void OWI_SendByte(unsigned char data, unsigned char pins)
{
  unsigned char temp;
  unsigned char i;
    
  // Do once for each bit
  for (i = 0; i < 8; i++)
  {
    // Determine if lsb is '0' or '1' and transmit corresponding
    // waveform on the bus.
    temp = data & 0x01;
    if (temp)
    {
      OWI_WriteBit1(pins);
    }
    else
    {
      OWI_WriteBit0(pins);
    }
    // Right shift the data to get next bit.
    data >>= 1;
  }
}

/*! \brief  Receives one byte of data from the 1-Wire(R) bus.
 *
 *  This function automates the task of receiving a complete byte 
 *  of data from the 1-Wire bus.
 *
 *  \param  pin     A bitmask of the bus to read from.
 *  
 *  \return     The byte read from the bus.
 */
unsigned char OWI_ReceiveByte(unsigned char pin)
{
  unsigned char data;
  unsigned char i;

  // Clear the temporary input variable.
  data = 0x00;
  
  // Do once for each bit
  for (i = 0; i < 8; i++)
  {
    // Shift temporary input variable right.
    data >>= 1;
    // Set the msb if a '1' value is read from the bus.
    // Leave as it is ('0') else.
    if (OWI_ReadBit(pin))
    {
      // Set msb
      data |= 0x80;
    }
  }
  return data;
}

/*! \brief  Sends the SKIP ROM command to the 1-Wire bus(es).
 *
 *  \param  pins    A bitmask of the buses to send the SKIP ROM command to.
 */
void OWI_SkipRom(unsigned char pins)
{
  // Send the SKIP ROM command on the bus.
  OWI_SendByte(OWI_ROM_SKIP, pins);
}

/*! \brief  Sends the READ ROM command and reads back the ROM id.
 *
 *  \param  romValue    A pointer where the id will be placed.
 *
 *  \param  pin     A bitmask of the bus to read from.
 */
void OWI_ReadRom(unsigned char * romValue, unsigned char pin)
{
  unsigned char bytesLeft = 8;

  // Send the READ ROM command on the bus.
  OWI_SendByte(OWI_ROM_READ, pin);
    
  // Do 8 times.
  while (bytesLeft > 0)
  {
    // Place the received data in memory.
    *romValue++ = OWI_ReceiveByte(pin);
    bytesLeft--;
  }
}

/*! \brief  Sends the MATCH ROM command and the ROM id to match against.
 *
 *  \param  romValue    A pointer to the ID to match against.
 *
 *  \param  pins    A bitmask of the buses to perform the MATCH ROM command on.
 */
void OWI_MatchRom(unsigned char * romValue, unsigned char pins)
{
  unsigned char bytesLeft = 8;   
    
  // Send the MATCH ROM command.
  OWI_SendByte(OWI_ROM_MATCH, pins);

  // Do once for each byte.
  while (bytesLeft > 0)
  {
    // Transmit 1 byte of the ID to match.
    OWI_SendByte(*romValue++, pins);
    bytesLeft--;
  }
}

/*! \brief  Sends the SEARCH ROM command and returns 1 id found on the 
 *          1-Wire(R) bus.
 *
 *  \param  bitPattern      A pointer to an 8 byte char array where the 
 *                          discovered identifier will be placed. When 
 *                          searching for several slaves, a copy of the 
 *                          last found identifier should be supplied in 
 *                          the array, or the search will fail.
 *
 *  \param  lastDeviation   The bit position where the algorithm made a 
 *                          choice the last time it was run. This argument 
 *                          should be 0 when a search is initiated. Supplying 
 *                          the return argument of this function when calling 
 *                          repeatedly will go through the complete slave 
 *                          search.
 *
 *  \param  pin             A bit-mask of the bus to perform a ROM search on.
 *
 *  \return The last bit position where there was a discrepancy between slave addresses the last time this function was run. Returns OWI_ROM_SEARCH_FAILED if an error was detected (e.g. a device was connected to the bus during the search), or OWI_ROM_SEARCH_FINISHED when there are no more devices to be discovered.
 *
 *  \note   See main.c for an example of how to utilize this function.
 */
/*
unsigned char OWI_SearchRom(unsigned char * bitPattern, unsigned char lastDeviation, unsigned char pin)
{
  unsigned char currentBit = 1;
  unsigned char newDeviation = 0;
  unsigned char bitMask = 0x01;
  unsigned char bitA;
  unsigned char bitB;

  // Send SEARCH ROM command on the bus.
  OWI_SendByte(OWI_ROM_SEARCH, pin);
    
  // Walk through all 64 bits.
  while (currentBit <= 64)
  {
    // Read bit from bus twice.
    bitA = OWI_ReadBit(pin);
    bitB = OWI_ReadBit(pin);

    if (bitA && bitB)
    {
      // Both bits 1 (Error).
      newDeviation = OWI_ROM_SEARCH_FAILED;
      return;
    }
    else if (bitA ^ bitB)
    {
      // Bits A and B are different. All devices have the same bit here.
      // Set the bit in bitPattern to this value.
      if (bitA)
      {
        (*bitPattern) |= bitMask;
      }
      else
      {
        (*bitPattern) &= ~bitMask;
      }
    }
    else // Both bits 0
    {
      // If this is where a choice was made the last time,
      // a '1' bit is selected this time.
      if (currentBit == lastDeviation)
      {
        (*bitPattern) |= bitMask;
      }
      // For the rest of the id, '0' bits are selected when
      // discrepancies occur.
      else if (currentBit > lastDeviation)
      {
        (*bitPattern) &= ~bitMask;
        newDeviation = currentBit;
      }
      // If current bit in bit pattern = 0, then this is
      // out new deviation.
      else if ( !(*bitPattern & bitMask)) 
      {
        newDeviation = currentBit;
      }
      // IF the bit is already 1, do nothing.
      else
      {
            
      }
    }
                
        
    // Send the selected bit to the bus.
    if ((*bitPattern) & bitMask)
    {
      OWI_WriteBit1(pin);
    }
    else
    {
      OWI_WriteBit0(pin);
    }

    // Increment current bit.    
    currentBit++;

    // Adjust bitMask and bitPattern pointer.    
    bitMask <<= 1;
    if (!bitMask)
    {
      bitMask = 0x01;
      bitPattern++;
    }
  }
  return newDeviation;
}
*/

仿真

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值