Nie zaleca się używać zmiennych globalnych bo na Tinkercad nie działają poprawnie.

ARE 2008
/**************************************/
/* ARE 2008 PTM 2 2024 */
/* e-mail: [email protected] */
/* www : are.net.pl */
/**************************************/
#define F_CPU 16000000UL // 16 MHz
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include <stdbool.h> // bool
#include <math.h> // pow()
#define DEBUG 0
#define RS 1 // 1 dane, 0 instrukcje
#define RW 2 // 1 odczytuje, 0 zapisuje
#define E 3 // L -> H -> L, odczytuje dane
void delay_ms(int ms) {
volatile long unsigned int i;
for(i=0;i<ms;i++)
_delay_ms(1);
}
void delay_us(int us) {
volatile long unsigned int i;
for(i=0;i<us;i++)
_delay_us(1);
}
void dioda_SET_CV() { PORTB |= (1 << PB4); }
void dioda_RESET_CV() { PORTB &= ~(1 << PB4); }
void LCD2x16_init(void) {
PORTC &= ~(1<<RS); // RS 0 komenda
PORTC &= ~(1<<RW); // RW 0 zapis
PORTC |= (1<<E); // E 1 Rozpoczęcie wprowadzania danych L -> H
PORTD = 0x38; // dwie linie, 5x7 punktow NKB 0011 1000
PORTC &=~(1<<E); // E 0 Zakończenie H -> L
_delay_us(120);
PORTC |= (1<<E);
PORTD = 0x0e; // wlacz wyswietlacz, kursor, miganie
PORTC &=~(1<<E);
_delay_us(120);
PORTC |= (1<<E);
PORTD = 0x06; // Nie przesuwaj obrazu
PORTC &=~(1<<E);
_delay_us(120);
}
void LCD2x16_clear(void){
PORTC &= ~(1<<RS); // RS 0
PORTC &= ~(1<<RW); // RW 0
PORTC |= (1<<E);
PORTD = 0x01; // Czyści wyświetlacz
PORTC &=~(1<<E);
delay_ms(120);
}
void LCD2x16_putchar(int data) {
PORTC |= (1<<RS); // RS 1 Wpisywanie
PORTC &= ~(1<<RW); // RW 0 dancyh
PORTC |= (1<<E);
PORTD = data;
PORTC &=~(1<<E);
_delay_us(120);
}
void LCD2x16_pos(int wiersz, int kolumna) {
PORTC &= ~(1<<RS); // RS 0
PORTC &= ~(1<<RW); // RW 0
PORTC |= (1<<E);
delay_ms(1); // 0x80-> Kursor na początek
PORTD = 0x80+(wiersz-1)*0x40+(kolumna-1);
delay_ms(1);
PORTC &=~(1<<E);
_delay_us(120);
}
Main
int main(void){
char start[17] = "PTM 2 W_________";
char data[17] = "30 X 2024 W____";
char tmp[16];
char tmp1[16];
char tmp2[16];
bool an_proc = false; // analogowy 1, procentowy 0
unsigned int stop_button = 0;
unsigned int display_delay = 0;
unsigned int liczba_petli = 10;
int i;
/* 100.00 = 10000 */
unsigned int SPp = 500; // 50 % = 0.5
unsigned int SPc ;
unsigned int Hp = 40; // 4 % = 0.04
unsigned int Hc ;
unsigned int UPmax = 5000; // 5 V
unsigned int Cmax = 40000; // 400 °C
unsigned int SPd = (unsigned int)round(1024*0.5-1);
unsigned int Hd = (unsigned int)round(1024*0.04-1);
long int Hd_2 = Hd / 2;
int Ed ;
//unsigned int PVd = SPd - Ed;
//unsigned int PVadc =
// unsigned int Eh = ?
// unsigned int Ep = Eh * Hp;
// unsigned int Ec = Ep * Cmax;
int Ep;
int Ec;
// unsigned int PVp = SPp - Ep;
unsigned int PVp ;
// unsigned int PVc = PVp * Cmax;
unsigned int PVc ;
// unsigned int PVv = PVp * UPmax;,
//Ep = SPp - PVp - UPmax;
unsigned int PV_A0 = 0;
/* USTAWIENIE PINÓW DO CZYTANIA */
DDRD = 0xff;
DDRC = 0xff;
DDRB = 0xff;
/* RESETOWANIE WSZYTKICH PINów */
// Rejestr odpowiedzialny za ustawianie wartości wyjściowych
PORTD = 0x00;
PORTC = 0x00;
PORTB = 0x00; // RESET
/* PRZESTAWIENIE PINÓW B i PC4 NA TYLKO ODCZYT (guziki) */
//DDRB = 0x00; // CZYTANIE B
//DDRB |= (1 << PB4);// ZAPIS PIN PB4 {Dioda}
DDRB = (1 << PB4); // ZAPIS PIN PB4 {Dioda} reszta PORTB CZYTANIE
DDRC &= ~(1 << PC0); // CZYTANIE PIN PC0 {Potencjometr}
DDRC &= ~(1 << PC4); // CZYTANIE PIN PC4 {Guzik [5] an_proc}
_delay_ms(200);
LCD2x16_init();
LCD2x16_clear();
for(i=0;i < 16;i++) LCD2x16_putchar(start[i]);
LCD2x16_pos(2,1);
for(i=0;i < 16;i++) LCD2x16_putchar(data[i]);
delay_ms(300);
// Ustawienie ADC
ADMUX = (1 << REFS0) | (0); // Ustaw referencję napięcia na AVcc, wybierz A0
ADCSRA = (1 << ADEN); // Włącz ADC
while(1) {
Ed = SPd - PV_A0;
/* ========= ODŚWIERZANIE co 0.5 s =========*/
if (display_delay == liczba_petli && DEBUG) {
LCD2x16_clear();
LCD2x16_pos(1,1);
for(i=0; i<16; ++i) LCD2x16_putchar(tmp1[i]);
LCD2x16_pos(2,1);
for(i=0; i<16; ++i) LCD2x16_putchar(tmp2[i]);
} else if (display_delay >= 2*liczba_petli) {
LCD2x16_clear();
display_delay = 0;
// Wyświetl wartość analogową
if(an_proc) {
//PVp = (int)round(PV_A0/10.23);
PVp = (int)(PV_A0/1.023);
SPp = (int)round((SPd+1)/10.24);
//sprintf(tmp, "SP=%2d%% PV=%4d%% ",SPp, PVp);
sprintf(tmp, "SP=%2d%% PV=%2d.%1d%% ",SPp, PVp/10,PVp%10);
} else {
PVc = (int)round( (PV_A0/(1023.0)) * Cmax );
SPc = (int)round( ((SPd+1)/102400.0)* Cmax );
sprintf(tmp, "SP=%2dC PV=%3d.%1dC",SPc, PVc/100, (PVc%100/10));
}
for(i = 0; i < 16; ++i) LCD2x16_putchar(tmp[i]);
LCD2x16_pos(2, 1);
if(an_proc) {
//Ep = (int)round( Ed/10.23 );
Ep = (int)( Ed/1.023 );
Hp = (int)round((Hd+1)/10.24);
sprintf(tmp, "H=%2d%% E=%3d.%1d%% ",Hp, Ep/10, abs(Ep%10));
//sprintf(tmp, "H=%2d%% E=%4d%% ",Hp, Ep);
//sprintf(tmp, "%10d ",Ed);
} else {
Ec = (int)round( (Ed/1023.0) * Cmax );
Hc = (int)round( ((Hd+1)/102400.0)* Cmax );
sprintf(tmp, "H=%2dC E=%3d.%1dC",Hc, Ec/100, abs(Ec%100/10));
}
for(i = 0; i < 16; ++i) LCD2x16_putchar(tmp[i]);
}
if(Ed > Hd_2) dioda_SET_CV();
else if(Ed < -Hd_2) dioda_RESET_CV();
/* ========= Odczyt wartości analogowej z A0 ========= */
ADCSRA |= (1 << ADSC); // Rozpocznij konwersję
while (ADCSRA & (1 << ADSC)); // Czekaj na zakończenie konwersji
PV_A0 = ADC; // Zapisz odczytaną wartość z ADC
/* ========= WYKRYWANIE WCIŚNIĘĆ GUZIKÓW ========= */
if (PINB == 0x0F && DEBUG) {
sprintf(tmp1,"PINB=0x%02X DATA=",PINB);
sprintf(tmp2,"PINC=0x%02X %s",PINC, an_proc ? "Analg" : "Proc%%");
} else if( !(PINB & (1 << PB0)) ) {
SPd = (int)round(1024*0.4-1);
} else if( !(PINB & (1 << PB1)) ) {
SPd = (int)round(1024*0.6-1);
} else if( !(PINB & (1 << PB2)) ) {
Hd = (int)round(1024*0.08-1);
Hd_2 = Hd / 2;
} else if( !(PINB & (1 << PB3)) ) {
Hd = (int)round(1024*0.1-1);
Hd_2 = Hd / 2;
}
if ( !(PINC & (1 << PC4)) && stop_button==0 ) {
an_proc = !an_proc;
stop_button = 4*liczba_petli;
} else if (stop_button > 0) --stop_button;
delay_ms(40);
++display_delay;
}
return 0;
}