📄 i2c_ds1631.c
字号:
// from scratch i2c to control the ds1631 temperature sensor
//
// Author: Dingo_aus
//
// Date: 14/12/2004
//
// This work is subject to Copryright. No reproduction is allowed without prior express consent of the author
//
// Contact: see http://www.users.on.net/~symes/Email.htm or pm Dingo_aus at www.avrfreaks.net
#include <avr/io.h>
#include "../avrlib/uart.h" //to allow easy uart communications (chews up about 1k of code space (1k left available))
#define DEV_DS1631 0x90 //I2C slave address of the ds1631 with a1-3 to GND
#define BIT_SCL 5 //SCL on PORT D, pin PD5
#define BIT_SDA 6 //SDA on PORT D, pin PD6
void delay(void);
void start(void);
void tx_byte(int);
int acknow(void);
void write_config(int);
void start_read_temp(void);
void read_temp(void);
char rx_byte(void);
u08 senddatum;
int temperature[2]; //global variable to store the actual temperature value
int main(void)
{
delay();
asm volatile ("cli"); //turn off interrupts
temperature[0] = 0;
temperature[1] = 0;
uartInit();
uartSetBaudRate(9600);
DDRD |= (1<<BIT_SDA); //set SDA pin as output
DDRD |= (1<<BIT_SCL); //set SCL pin as output
PORTD |=(1<<BIT_SDA); //SDA high
PORTD |=(1<<BIT_SCL); //SCL high
write_config(0x0f);
start_read_temp();
read_temp();
}
void delay()
{
//the original delay code filled two registers with 0XFF then decremented both loops,
//one inside the other. Total delay .0244 seconds
//This "for" loop gives approximately the same delay
for(int temp = 63000; temp<1 ;temp--)
{
asm volatile("nop");
}
return;
}
//sends start condition on the I2C bus
void start(void)
{
//different to 24LC256 code.
//DS1631 datasheet says SCL high then SDA goes low to indicate START
//PORTD |= (1<< BIT_SCL);
//PORTD |= (1<<BIT_SCL);
PORTD |= (1 << BIT_SCL);
PORTD &= ~(1 << BIT_SDA);
}
void tx_byte(int value)
{
for(int n=0;n<=7;n++)
{
//take it high
PORTD |= (1<<BIT_SDA);
//look at the left (MSB) most byte of temp
if(!(value & 0x80)) //if left most byte is 0 then....
{
//SDA low
PORTD &= ~(1<<BIT_SDA);
}
//left shift so next loop iteration deals with next value
value = value<<1;
//pulse clock line
PORTD |=(1<<BIT_SCL); //high
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
PORTD &= ~(1<<BIT_SCL); //low
}
return;
}
//checks if the ack bit came back (maybe add a delay? --A: called in a loop - no need for delay)
int acknow(void)
{
//change DDRD:take SDA low on DDRD (make input)
DDRD &= ~(1 << BIT_SDA);
//take SDA high
PORTD |= (1<<BIT_SDA);
//set carry flag
int tempret = 1;
//take SCL high
PORTD |=(1<<BIT_SCL);
asm volatile ("nop");
asm volatile ("nop");
//if SDA low then clear the carry flag
if(!((PIND & 0x40)==0x40)) //check if SDA is low (hard coded to PD6)
{
senddatum = '-';
uartSendByte(senddatum);
tempret = 0; //success
}
//take SCL low
PORTD &= ~(1 << BIT_SCL);
//make SDA oupput again by changign DDRD
DDRD |= (1<<BIT_SDA);
//return
return tempret;
}
void write_config(int config)
{
int done = 0;
while(!done)
{
PORTD &= ~(1 << BIT_SDA);//send start condition (take lines low)
PORTD &= ~(1 << BIT_SCL);
tx_byte(0x90); //send the slave address so correct slave picks up
if(acknow())
{
senddatum = '1';
uartSendByte(senddatum);
continue;
}
tx_byte(0xAC); //send the access configuration command
if(acknow())
{
senddatum = '2';
uartSendByte(senddatum);
continue;
}
tx_byte(config); //POL is active high, and 1SHOT mode, 12-bit precision
if(acknow())
{
continue;
}
//Now create a stop condition
PORTD &= ~(1<<BIT_SDA);
PORTD |= (1<<BIT_SCL); //stop condition
PORTD |= (1<<BIT_SDA);
senddatum = 'O';
uartSendByte(senddatum);
senddatum = 'K';
uartSendByte(senddatum);
done = 1;
}
return;
}
void start_read_temp()
{
int done = 0;
while(!done)
{
//This start assumes last routine left lines high (ie proper STOP condition, then idle)
PORTD &= ~(1 << BIT_SDA);//send start condition (take lines low)
PORTD &= ~(1 << BIT_SCL);
tx_byte(0x90); //send the slave address so correct slave picks up
if(acknow())
{
senddatum = '4';
uartSendByte(senddatum);
continue;
}
tx_byte(0x51); //send the Start temperature conversion command - for 1SHOT mode it automatically stops after this
if(acknow())
{
senddatum = '5';
uartSendByte(senddatum);
continue;
}
PORTD &= ~(1<<BIT_SDA);
PORTD |= (1<<BIT_SCL); //stop condition
PORTD |= (1<<BIT_SDA);
senddatum = 's';
uartSendByte(senddatum);
senddatum = 't';
uartSendByte(senddatum);
senddatum = 'a';
uartSendByte(senddatum);
senddatum = 'r';
uartSendByte(senddatum);
senddatum = 't';
uartSendByte(senddatum);
senddatum = 'e';
uartSendByte(senddatum);
senddatum = 'm';
uartSendByte(senddatum);
senddatum = 'p';
uartSendByte(senddatum);
done = 1 ;
}
return;
}
//Function to read the temp stored during start_read_temp()
//Value is two bytes and stored in a global variable (no array passed to this function at this stage)
void read_temp(void)
{
int done = 0;
while(!done)
{
//This start assumes last routine left lines high (ie proper STOP condition, then idle)
PORTD &= ~(1 << BIT_SDA);//send start condition (take lines low)
PORTD &= ~(1 << BIT_SCL);
tx_byte(0x90); //send the slave address so correct slave picks up
if(acknow())
{
senddatum = '6';
uartSendByte(senddatum);
continue;
}
tx_byte(0xAA); //send the command to read the temp
if(acknow())
{
senddatum = '7';
uartSendByte(senddatum);
continue;
}
//Need to repeat the start condition to change to read mode
PORTD |= (1<<BIT_SDA);
PORTD |= (1<<BIT_SCL);
//delay??
PORTD &= ~(1<<BIT_SDA);
//had problem before without this (as long as SDA goes down first)
PORTD &= ~(1<<BIT_SCL);
tx_byte(0x91); //send the slave address but with R/W bit set to 1 for read
if(acknow())
{
senddatum = '8';
uartSendByte(senddatum);
continue;
}
//read in MSB
temperature[0] = rx_byte();
//send ack signal
PORTD |= (1<<BIT_SDA);
PORTD |= (1<<BIT_SCL);
PORTD &= ~(1<<BIT_SCL);
PORTD &= ~(1<<BIT_SDA);
//pulse SCL
PORTD |= (1<<BIT_SCL);
//leaving SDA low
asm volatile ("nop");
PORTD &= ~(1<<BIT_SCL);
PORTD |= (1<<BIT_SDA);
PORTD |= (1<<BIT_SCL);
temperature[1] = rx_byte();
PORTD &= ~(1<<BIT_SDA);
PORTD |= (1<<BIT_SCL); //stop condition
PORTD |= (1<<BIT_SDA);
senddatum = 13;
uartSendByte(senddatum);
senddatum = 't';
uartSendByte(senddatum);
senddatum = 'e';
uartSendByte(senddatum);
senddatum = 'm';
uartSendByte(senddatum);
senddatum = 'p';
uartSendByte(senddatum);
senddatum = 'r';
uartSendByte(senddatum);
senddatum = 'e';
uartSendByte(senddatum);
senddatum = 'a';
uartSendByte(senddatum);
senddatum = 'd';
uartSendByte(senddatum);
senddatum = ':';
uartSendByte(senddatum);
senddatum = temperature[0];
uartSendByte(senddatum);
senddatum = temperature[1];
uartSendByte(senddatum);
done = 1 ;
}
return;
}
char rx_byte(void)
{
//char retval = 0x00;//TEMP = 0x0000
int flag=0;
DDRD &= ~(1<<BIT_SDA); //SDA made input
PORTD |=(1<<BIT_SDA); //set SDA high
int temprxval = 0;
for(int t=0; t<=7; t++) //need to step through each bit received from the bus
{
PORTD |= (1<<BIT_SCL);
flag = 1;
if(!((PIND & 0x40)==0x40)) //if SDA low
{
flag = 0;
senddatum = '0';
uartSendByte(senddatum);
}
else
{
senddatum = '1';
uartSendByte(senddatum);
}
temprxval = (temprxval << 1);
temprxval = temprxval | flag;
//retval = retval | flag;
//retval = retval<<1;
//retval++;
PORTD &= ~(1<<BIT_SCL);
}
senddatum = 13;
uartSendByte(senddatum);
//senddatum = temprxval;
//uartSendByte(senddatum);
DDRD |=(1<<BIT_SDA); //SDA made output again
return temprxval;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -