Witam
Chcę skonstruować urządzenie, które oprócz zegarka mierzyłoby jednocześnie temperaturę i obydwie wielkości wyświetlałoby na wyświetlaczu LCD. Gdy programy napisałem osobno, obydwa działały, lecz gdy połączyłem je w całość, to czas odczytuję bez problemu, natomiast nie wyświetla mi się temperatura. Podejrzewam, że problem jest w przerwaniach. Poniżej kod. Proszę o pomoc.
Dodano po 4 [minuty]:
Zapomniałem dodać, że program musi być zrobiony na przerwaniach. Czas konwersji temperatury czujnika DS18B20 to 750ms i gdybym nie używał przerwań, to program nie wyświetlałby sekund w stałym przedziale czasu. Mając przerwania jestem pewien, że takiego problemu nie będzie. Pozdrawiam!
Chcę skonstruować urządzenie, które oprócz zegarka mierzyłoby jednocześnie temperaturę i obydwie wielkości wyświetlałoby na wyświetlaczu LCD. Gdy programy napisałem osobno, obydwa działały, lecz gdy połączyłem je w całość, to czas odczytuję bez problemu, natomiast nie wyświetla mi się temperatura. Podejrzewam, że problem jest w przerwaniach. Poniżej kod. Proszę o pomoc.
#include <avr/io.h> // dostęp do rejestrów
#include <util/delay.h>
#include <avr/interrupt.h>
#define F_CPU 8000000UL
#include "HD44780.c"
#define UART_BAUD 19200
#define UART_CONST (F_CPU/(16ul*UART_BAUD)-1)
#define LOOP_CYCLES 8 //Number of cycles that the loop takes
#define us(num) (num/(LOOP_CYCLES*(1/(F_CPU/1000000.0))))
/* Thermometer Connections (At your choice) */
#define THERM_PORT PORTD
#define THERM_DDR DDRD
#define THERM_PIN PIND
#define THERM_DQ 5
/* Utils */
#define THERM_INPUT_MODE() THERM_DDR&=~(1<<THERM_DQ)
#define THERM_OUTPUT_MODE() THERM_DDR|=(1<<THERM_DQ)
#define THERM_LOW() THERM_PORT&=~(1<<THERM_DQ)
#define THERM_HIGH() THERM_PORT|=(1<<THERM_DQ)
#define THERM_CMD_CONVERTTEMP 0x44
#define THERM_CMD_RSCRATCHPAD 0xbe
#define THERM_CMD_WSCRATCHPAD 0x4e
#define THERM_CMD_CPYSCRATCHPAD 0x48
#define THERM_CMD_RECEEPROM 0xb8
#define THERM_CMD_RPWRSUPPLY 0xb4
#define THERM_CMD_SEARCHROM 0xf0
#define THERM_CMD_READROM 0x33
#define THERM_CMD_MATCHROM 0x55
#define THERM_CMD_SKIPROM 0xcc
#define THERM_CMD_ALARMSEARCH 0xec
#define THERM_DECIMAL_STEPS_12BIT 625 //.0625
volatile unsigned char licznik_przycisku_1, licznik_przycisku_2;
volatile uint16_t licznik_przerwan;
uint8_t licznik_wcisniecia, znacznik_zbocza_1=0, znacznik_zbocza_2=0;
volatile unsigned char godziny,minuty,sekundy,czy_wybrano_zmiane;
volatile char znak;
volatile uint16_t digit;
volatile uint16_t decimal;
volatile uint8_t temperature[2];
volatile char buffer[11];
inline __attribute__((gnu_inline)) void therm_delay(uint16_t delay)
{
while(delay--) asm volatile("nop");
}
//======================= TWI ===========================================
void TWI_start(void)
{
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
}
void TWI_stop(void)
{
TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
while((TWCR&(1<<TWSTO)));
}
void TWI_write(char dane)
{
TWDR = dane;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
}
unsigned char TWI_read(unsigned char ack)
{
TWCR =(1<<TWINT)|(ack<<TWEA)|(1<<TWEN);
while (!(TWCR&(1<<TWINT)));
return TWDR;
}
//==========================================================================
//======================= 1-WIRE ===========================================
uint8_t therm_reset()
{
uint8_t i;
//Pull line low and wait for 480uS
THERM_LOW();
THERM_OUTPUT_MODE();
therm_delay(us(480));
//Release line and wait for 60uS
THERM_INPUT_MODE();
therm_delay(us(60));
//Store line value and wait until the completion of 480uS period
i=(THERM_PIN & (1<<THERM_DQ));
therm_delay(us(420));
//Return the value read from the presence pulse (0=OK, 1=WRONG)
return i;
}
void therm_write_bit(uint8_t bit)
{
cli();
//Pull line low for 1uS
THERM_LOW();
THERM_OUTPUT_MODE();
therm_delay(us(1));
//If we want to write 1, release the line (if not will keep low)
if(bit) THERM_INPUT_MODE();
//Wait for 60uS and release the line
therm_delay(us(60));
THERM_INPUT_MODE();
sei();
}
uint8_t therm_read_bit(void)
{
cli();
uint8_t bit=0;
//Pull line low for 1uS
THERM_LOW();
THERM_OUTPUT_MODE();
therm_delay(us(1));
//Release line and wait for 14uS
THERM_INPUT_MODE();
therm_delay(us(14));
//Read line value
if(THERM_PIN&(1<<THERM_DQ)) bit=1;
//Wait for 45uS to end and return read value
therm_delay(us(45));
sei();
return bit;
}
//===========================================================================
uint8_t therm_read_byte(void)
{
uint8_t i=8, n=0;;
while(i--)
{
//Shift one position right and store read value
n>>=1;
n|=(therm_read_bit()<<7);
}
return n;
}
void therm_write_byte(uint8_t byte)
{
uint8_t i=8;
while(i--)
{
//Write actual bit and shift one position right to make
// the next bit ready
therm_write_bit(byte&1);
byte>>=1;
}
}
void therm_read_temperature()
{
// Buffer length must be at least 12bytes long! ["+XXX.XXXX C"]
//Reset, skip ROM and start temperature conversion
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_CONVERTTEMP);
//Wait until conversion is complete
while(!therm_read_bit());
//Reset, skip ROM and send command to read Scratchpad
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_RSCRATCHPAD);
//Read Scratchpad (only 2 first bytes)
temperature[0]=therm_read_byte();
temperature[1]=therm_read_byte();
therm_reset();
//Store temperature integer digits and decimal digits
digit=temperature[0]>>4;
digit|=(temperature[1]&0x7)<<4;
//Store decimal digits
decimal=temperature[0]&0xf;
decimal*=THERM_DECIMAL_STEPS_12BIT;
// Format temperature into a string [+XXX.XXXX C]
sprintf(buffer, "%04d.%04u C", digit, decimal);
}
//======================== PCF8583P ==================================
void rtc_write(unsigned char adres,unsigned char dane)
{
TWI_start();
TWI_write(0xA0);
TWI_write(adres);
TWI_write(dane);
TWI_stop();
_delay_ms(15);
}
unsigned char rtc_read(unsigned char adres)
{
char odczyt;
TWI_start();
TWI_write(0xA0);
TWI_write(adres);
TWI_start();
TWI_write(0xA1);
odczyt=TWI_read(0);
TWI_stop();
return odczyt;
}
unsigned char Bcd2dec(unsigned char bcd)
{
return 10*(bcd>>4)+bcd&0x0F;
}
void lcd_rtc_read()
{
char g,m,s;
LCD_GoTo(4,0);
g=rtc_read(0x04);
LCD_WriteData(Bcd2dec(g>>4)+0x30);
LCD_WriteData(Bcd2dec(g&0x0f)+0x30);
LCD_WriteText(":");
LCD_GoTo(7,0);
m=rtc_read(0x03);
LCD_WriteData(Bcd2dec(m>>4)+0x30);
LCD_WriteData(Bcd2dec(m&0x0f)+0x30);
LCD_WriteText(":");
s=rtc_read(0x02);
LCD_GoTo(10,0);
LCD_WriteData(Bcd2dec(s>>4)+0x30);
LCD_WriteData(Bcd2dec(s&0x0f)+0x30);
}
void lcd_rtc_write(char g, char m, char s)
{
rtc_write(0x02,g);
rtc_write(0x03,m);
rtc_write(0x04,s);
}
//============================================================
SIGNAL(SIG_OVERFLOW0) //procedura obsługi przerwania zewnetrznego INT0
{
TCNT0 = 0x22;
//--------------------------------------------------------pierwszy przycisk
if(bit_is_clear(PINC,2) && znacznik_zbocza_1==0)
{
licznik_przycisku_1++;
znacznik_zbocza_1=1;
LCD_Clear();
}
if(bit_is_set(PINC,2))
{
_delay_ms(100); //opóźnienie w celu ustabilizowania się wyłączenia styku
znacznik_zbocza_1=0;
}
//-------------------------------------------------------------------------
//----------------------------------------------------------drugi przycisk
if(bit_is_clear(PINC,5) && znacznik_zbocza_2==0)
{
licznik_przycisku_2=1;
znacznik_zbocza_2=1;
}
//-------------------------------------------------------------------------
if(licznik_przycisku_1==0)
{
lcd_rtc_read();
}
if ((licznik_przycisku_1==1) && (czy_wybrano_zmiane==0))
{
godziny = rtc_read(0x04);
minuty = rtc_read(0x03);
sekundy = rtc_read(0x02);
czy_wybrano_zmiane = 1;
}
if ((licznik_przycisku_1==1) && (czy_wybrano_zmiane==1)) //ustawienie godzin
{
LCD_GoTo(4,0);
if (licznik_przycisku_2==1)
{
godziny++;
if((godziny&0x0f)>9)
{
godziny+=0x06; //korekcja dziesietna liczby BCD
}
if (godziny > 0x23)
godziny = 0x00;
}
LCD_WriteData(Bcd2dec(godziny>>4)+0x30);
LCD_WriteData(Bcd2dec(godziny&0x0f)+0x30);
LCD_WriteText(":");
}
if ((licznik_przycisku_1==2) && (czy_wybrano_zmiane==1)) //ustawienie minut
{
LCD_GoTo(7,0);
if (licznik_przycisku_2==1)
{
minuty++;
if((minuty&0x0f)>9)
{
minuty+=0x06; //korekcja dziesietna liczby BCD
}
if(minuty>0x59) //korekcja przekroczenia wartosci 59
minuty&=0; //przeniesienia na godziny nie ma
}
LCD_WriteText(":");
LCD_WriteData(Bcd2dec(minuty>>4)+0x30);
LCD_WriteData(Bcd2dec(minuty&0x0f)+0x30);
LCD_WriteText(":");
}
if ((licznik_przycisku_1==3) && (czy_wybrano_zmiane==1)) //ustawienie sekund
{
LCD_GoTo(10,0);
if (licznik_przycisku_2==1)
{
sekundy++;
if((sekundy&0x0f)>9)
{
sekundy+=0x06; //korekcja dziesietna liczby BCD
}
if(sekundy>0x59) //korekcja przekroczenia wartosci 59
sekundy&=0; //przeniesienia na godziny nie ma
}
LCD_WriteText(":");
LCD_WriteData(Bcd2dec(sekundy>>4)+0x30);
LCD_WriteData(Bcd2dec(sekundy&0x0f)+0x30);
}
//-----------------------------KASOWANIE PRZYCISKU 2----------------------------
if(licznik_przycisku_2==1)
licznik_przycisku_2=0;
if(bit_is_set(PINC,5))
{
_delay_ms(100); //opóźnienie w celu sutabilizowania się wyłączenia styku
znacznik_zbocza_2=0;
}
//-------------------------------------------------------------------------------
if(licznik_przycisku_1==4)
{
rtc_write(0x02,sekundy);
rtc_write(0x03,minuty);
rtc_write(0x04,godziny);
licznik_przycisku_1 = 0;
czy_wybrano_zmiane=0;
}
LCD_GoTo(0,1);
LCD_WriteText(buffer);
}
int main(void) // program główny
{
TCNT0 = 0x22;
TCCR0 = 0x02;
OCR0 = 250;
TIMSK = 1 <<TOIE0;
DDRC = _BV(0)|_BV(1);
PORTC = 0x3C;
LCD_Initalize();
sei();
while(1)
{
therm_read_temperature();
}
}
Dodano po 4 [minuty]:
Zapomniałem dodać, że program musi być zrobiony na przerwaniach. Czas konwersji temperatury czujnika DS18B20 to 750ms i gdybym nie używał przerwań, to program nie wyświetlałby sekund w stałym przedziale czasu. Mając przerwania jestem pewien, że takiego problemu nie będzie. Pozdrawiam!