⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thermo.c

📁 一个单片机的I2C驱动程序
💻 C
字号:

/*
  Jesper Hansen <jesperh@telia.com>

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation, 
  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.





  	Thermostat regulator with Dallas DS1621.
  	----------------------------------------	
    
  	2000-11-24  



	CPU: At90S2313

	Switches are at PD2 and PD3, common ground

 	LED segments a-g are at PB0 - PB7, and
 	the anodes are at PD0 and PD1
 	The relay are at PD6, active high

 	Dallas DS1621 I2C bus are connected at 
 	PD4 = SDA 
 	PD5 = SCL

*/


#include <io.h>
#include <io.h>
#include <progmem.h>
#include <eeprom.h>
#include <signal.h>
#include <interrupt.h>

#include "delay.h"
#include "i2c.h"



// PORT D
#define KEYUP	PD2
#define KEYDN	PD3

#define	LED1	PD0
#define LED2	PD1

#define SDA		PD4
#define SCL		PD5

#define RELAY	PD6


// PORT B

#define SEG_a	0x01
#define SEG_b	0x02
#define SEG_c	0x04
#define SEG_d	0x08
#define SEG_e	0x10
#define SEG_f	0x20
#define SEG_g	0x40
#define SEG_dot	0x80

// MISC

// eeprom storage positions
#define EEPROM_SETTEMP		0x11
#define EEPROM_HYSTERESIS	0x13
#define EEPROM_DUTYVALUE	0x15


#define BLINKCOUNT	80

#define KEY_UP		0x01
#define KEY_DOWN 	0x02
#define KEY_BOTH	(KEY_UP|KEY_DOWN)

//
// mode setting enums
//
typedef enum mode_e
{
	NORMAL,
	SET_HYST,
	SET_DUTY,
} mode_e;


mode_e next_mode[] = {SET_HYST, SET_DUTY, NORMAL};
mode_e mode = NORMAL;

unsigned char digits[] = {
	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f),			// 0
	(SEG_b|SEG_c),									// 1
	(SEG_a|SEG_b|SEG_d|SEG_e|SEG_g),				// 2
	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_g),				// 3
	(SEG_b|SEG_c|SEG_c|SEG_f|SEG_g),				// 4
	(SEG_a|SEG_c|SEG_d|SEG_f|SEG_g),				// 5
	(SEG_a|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g),			// 6
	(SEG_a|SEG_b|SEG_c),							// 7
	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g),	// 8
	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_f|SEG_g),			// 9
	(SEG_a),										// mode 1 indicator
	(SEG_g),										// mode 2 indicator
	(SEG_d),										// mode 3 indicator
};



unsigned char set_temp = 20;		// initial set temperature
unsigned char set_flag = 0;			// no settings in progress

unsigned char hysteresis = 1;		// initial hysteresis
unsigned char dutyvalue = 3;		// initial duty-cycle
unsigned char relay_on = 0;			// initial relay state



// timer 0 handles multiplex and refresh of the displays

#define TI0_L		(256-64)	

volatile unsigned char flip = 0;
volatile unsigned char dutycount = 0;
volatile unsigned char temp = 20;
unsigned char dotcount = BLINKCOUNT;

SIGNAL(SIG_OVERFLOW0)	//timer 0 overflow
{
	unsigned char b = 0;

	// reload timer
	outp(TI0_L, TCNT0);

	// both displays off

	sbi(PORTD, LED1);
	sbi(PORTD, LED2);

	dutycount++;
	if (dutycount == dutyvalue)
	{
		dutycount = 0;

		switch (mode)
		{
			case NORMAL:
				// see which one we need to update
				if (flip)	// high ?
					b = (temp / 10);
				else
					b = temp % 10;
				break;

			case SET_HYST :
				// see which one we need to update
				if (flip)	// high ?
					b = 10;	// mode indicator
				else
					b = hysteresis;
				break;

			case SET_DUTY :
				// see which one we need to update
				if (flip)	// high ?
					b = 11;	// mode indicator
				else
					b = dutyvalue;
				break;
				
		}

		// set digit data on port
		outp(digits[b], PORTB);

		if (flip)	// left LED
		{
			if (dotcount < BLINKCOUNT/2)
				sbi(PORTB,7);
				
			if (dotcount)
				dotcount--;
			else
				dotcount = BLINKCOUNT;	
		
			cbi(PORTD, LED1);
		}
		else
		{
			if (relay_on)
				sbi(PORTB,7);
			
			cbi(PORTD, LED2);
		}
		
		flip = !flip;
	}
}




void start_timer_0(void)
{
	//setup timer 0

	outp(0x03, TCCR0);		// prescaler /64  tPeriod = 10.667 uS
	sbi(TIMSK, TOIE0);	 	// enable timer1 interrupt
	outp(TI0_L,TCNT0);		// load timer  

	sei();					// start timer by enabling interrupts
}



int getkey(void)
{
	int ret_val = 0;

	// if none of the keys are down,
	// return zero
	if (bit_is_set(PIND, KEYUP) && bit_is_set(PIND, KEYDN) )
		return 0;

	// debounce 80 mS
	delay(40000);	
	delay(40000);	
		
	// now read again and return status
	if (bit_is_clear(PIND, KEYUP))
		ret_val |= KEY_UP;

	if (bit_is_clear(PIND, KEYDN))
		ret_val |= KEY_DOWN;

	return ret_val;
}			



int main(void) 
{
	unsigned char i2cdata[8];

	// set port B as all outputs
	// and initially set all pins HI

	outp(0xff,PORTB);
	outp(0xff,DDRB);


	// set common LED pins as output
	// and initially set them HI
	// set RELAY pin as output, and initially set it LO (off)
	// also activate pullups on keyboard inputs
	outp((1<<LED1)|(1<<LED2)|(1<<RELAY),DDRD);
	outp((1<<LED1)|(1<<LED2)|(1<<KEYUP)|(1<<KEYDN),PORTD);

	i2c_init();

	// restore data from eeprom
	// and make sure values are sane
	set_temp = eeprom_rb(EEPROM_SETTEMP);
	if (set_temp > 40 || set_temp < 1)
		set_temp = 20;

	hysteresis = eeprom_rb(EEPROM_HYSTERESIS);
	if (hysteresis > 5)
		hysteresis = 1;

	dutyvalue = eeprom_rb(EEPROM_DUTYVALUE);
	if (dutyvalue > 10 || dutyvalue < 1)
		dutyvalue = 3;


	// Setup DS1621

	// Access Config Command 
	// Set Continuous transfer, polarity active lo
	i2c_send(0x90, 0xAC, 1, "\0x00");
	delay(1000);

	// Start conversion
	i2c_send(0x90, 0xEE, 0, 0);


	// start the timer
	start_timer_0();



	while (1)
	{
		// check switch status
		
		if (temp >= set_temp+hysteresis)
		{
			relay_on = 0;
			cbi(PORTD, RELAY);				// relay OFF
		}
			
		if (temp <= set_temp-hysteresis)
		{
			relay_on = 1;
			sbi(PORTD, RELAY);				// relay ON
		}	
			
			
		// check keys			
			
		switch (getkey())			
		{
			case KEY_UP :
				if (set_flag)		// don't change set_temp on first press
				{
					switch (mode)
					{
						case NORMAL :
							set_temp++;		// increment set temperature
							break;
						case SET_HYST :							
							hysteresis++;	// increment hysteresis
							break;
						case SET_DUTY :
							dutyvalue++;	// increment duty value
							break;
					}
				}	
				set_flag = 50;		// set timeout flag for display
				break;

			case KEY_DOWN :
				if (set_flag)		// don't change set_temp on first press
				{
					switch (mode)
					{
						case NORMAL :
							set_temp--;		// decrement set temperature
							break;
						case SET_HYST :							
							hysteresis--;	// decrement hysteresis
							break;
						case SET_DUTY :
							dutyvalue--;	// decrement duty value
							break;
					}

				}	
				set_flag = 50;		// set timeout flag for display
				break;
				
			case KEY_BOTH :	
				mode = next_mode[mode];
				set_flag = 50;
				break;
			
		}



		delay(10000);
			
		if (set_flag)
		{
			set_flag--;
			if (set_flag == 0)
			{
				switch (mode)
				{
					case NORMAL:
						eeprom_wb(EEPROM_SETTEMP,set_temp);
						break;
					case SET_HYST :
						eeprom_wb(EEPROM_HYSTERESIS,hysteresis);
						break;
					case SET_DUTY :
						eeprom_wb(EEPROM_DUTYVALUE,dutyvalue);
						break;
				}						
					
				mode = NORMAL;
			}
			temp = set_temp;
		}
		else
		{
			// read temp
			i2c_receive(0x90,0xAA, 2, i2cdata);
			temp = *i2cdata;
		}
	
	
	}




}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -