代码:
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;
}
*/
仿真