evo ga finalni kod ako nekog zanima ...
Code:
#include <16F819.h>
#device adc=10
#FUSES INTRC_IO
#FUSES WDT
#FUSES NOPROTECT
#FUSES NOBROWNOUT
#FUSES MCLR
#FUSES NOCPD
#FUSES NOPUT
#FUSES NOLVP
#use delay(clock=4000000)
#use i2c(Slave,Fast,sda=PIN_B1,scl=PIN_B4,restart_wdt,force_hw,address=0xAB)
char init1[] = "HEAT BED CONTROL";
char init2[] = " v2.1 ";
char gen1[] = "Target: 00.00C";
char gen2[] = "Current: 00.00C";
volatile unsigned int16 i;
volatile unsigned int8 j;
unsigned int16 adc_raw;
unsigned int16 adc_avg;
unsigned int16 target;
unsigned int16 current;
//204-GT thermistor with 10K in voltage divider
#define TEMPS 28
unsigned int16 thermTable[TEMPS] = {
1010, 1000, 985, 963, 932, 889, 834, 768, 692, 610, //0-90
526, 446, 373, 308, 252, 206, 168, 137, 112, 91, //100-190
75, 62, 51, 43, 36, 30, 26, 22 // 200-270
};
BYTE incoming, state;
BYTE address;
BYTE buffer[4]; //[0] + [1]<<8 = TARGET TEMP; [2] + [3]<<8 = CURRENT TEMP
BYTE changed;
#int_SSP
void SSP_isr(void) {
state = i2c_isr_state();
if(state == 1){
incoming = i2c_read();
address = incoming;
if (address > 3) address = 0;
}
if(state == 2){
incoming = i2c_read();
if (address > 1) address = 0; //only 0 and 1 are writable
buffer[address] = incoming;
if (address == 1) changed = 1; //set changed only when second byte is written
}
if(state == 0x80){
i2c_write (buffer[address]);
}
}
//RB3 - RS
struct lcd_pin_map {
BOOLEAN unused;
int data : 4;
BOOLEAN mclr;
BOOLEAN rw;
BOOLEAN enable;
} lcd;
#locate lcd = getenv("sfr:PORTA")
#define set_tris_lcd(x) set_tris_a(x)
#define lcd_type 2
#define lcd_line_two 0x40
BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
struct lcd_pin_map const LCD_WRITE = {1, 0,0,0,0}; // For write mode all pins are out
struct lcd_pin_map const LCD_READ = {1,15,0,0,0}; // For read mode data pins are in
BYTE lcd_read_byte() {
BYTE low,high;
set_tris_lcd(LCD_READ);
lcd.rw = 1;
delay_cycles(1);
lcd.enable = 1;
delay_cycles(1);
high = lcd.data;
lcd.enable = 0;
delay_cycles(1);
lcd.enable = 1;
delay_us(1);
low = lcd.data;
lcd.enable = 0;
set_tris_lcd(LCD_WRITE);
return( (high<<4) | low);
}
void lcd_send_nibble( BYTE n ) {
lcd.data = n;
delay_cycles(1);
lcd.enable = 1;
delay_us(2);
lcd.enable = 0;
}
void lcd_send_byte( BYTE address, BYTE n ) {
//lcd.rs = 0;
output_low(PIN_B3);
while ( bit_test(lcd_read_byte(),7) ) ;
//lcd.rs = address;
if (address){
output_high(PIN_B3);
}else{
output_low(PIN_B3);
}
delay_cycles(1);
lcd.rw = 0;
delay_cycles(1);
lcd.enable = 0;
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
void lcd_init() {
BYTE i;
set_tris_lcd(LCD_WRITE);
//lcd.rs = 0;
output_low(PIN_B3);
lcd.rw = 0;
lcd.enable = 0;
delay_ms(15);
for(i=1;i<=3;++i) {
lcd_send_nibble(3);
delay_ms(5);
}
lcd_send_nibble(2);
for(i=0;i<=3;++i)
lcd_send_byte(0,LCD_INIT_STRING[i]);
}
unsigned int16 getTemp(){
// adc_avg -raw data from adc 10bit
// thermTable -data from 0 - 270deg every 10 deg
unsigned int16 tempVal;
unsigned int16 lowValue;
unsigned int16 highValue;
unsigned int16 dataValue;
unsigned int16 range;
for(j=0; j<TEMPS; ++j){
tempVal = thermTable[j];
if (adc_avg > tempVal){
#asm
clrwdt
#endasm
lowValue = tempVal;
highValue = thermTable[j-1];
range = highValue - lowValue;
dataValue = adc_avg - LowValue;
return j * 1000 - (dataValue * 1000 / range);
}
}
return (55555);
}
void print_temp(int8 line, unsigned int16 temp){ // temperature is *100
unsigned int8 x;
//hundreds
x = temp / 10000;
if (x == 0) {
//Lcd_Chr(line, 10, ' ');
lcd_send_byte(0,0x80|(10+lcd_line_two*line));
lcd_send_byte(1,' ');
} else {
x = x + 48;
//Lcd_Chr(line, 10, x);
lcd_send_byte(0,0x80|(10+lcd_line_two*line));
lcd_send_byte(1, x);
}
#asm
clrwdt
#endasm
//tens
x = ((temp / 1000 ) % 10) + 48;
//Lcd_Chr(line, 11, x);
lcd_send_byte(0,0x80|(11+lcd_line_two*line));
lcd_send_byte(1, x);
#asm
clrwdt
#endasm
//ones
x = ((temp / 100 ) % 10) + 48;
//Lcd_Chr(line, 12, x);
lcd_send_byte(0,0x80|(12+lcd_line_two*line));
lcd_send_byte(1, x);
#asm
clrwdt
#endasm
// 1/10
x = ((temp / 10 ) % 10) + 48;
//Lcd_Chr(line, 14, x);
lcd_send_byte(0,0x80|(14+lcd_line_two*line));
lcd_send_byte(1, x);
#asm
clrwdt
#endasm
// 1/100
x = (temp % 10) + 48;
//Lcd_Chr(line, 15, x);
lcd_send_byte(0,0x80|(15+lcd_line_two*line));
lcd_send_byte(1, x);
#asm
clrwdt
#endasm
}
void pid(){ //for start - very basic pid controller
if (current < target){
output_low(PIN_B2);
} else {
output_high(PIN_B2);
}
}
//RB0, RB5
void menu(){
#asm
clrwdt
#endasm
if (!input(PIN_B0)) if(target<27000) target += 50;
if (!input(PIN_B5)) if(target>49) target -= 50;
if (!input(PIN_B0) && !input(PIN_B5)){
write_eeprom(0, target & 0x00ff);
write_eeprom(1, target >> 8 );
}
print_temp(0, target);
}
void main(){
//OSCCON = 0x40; //1MHZ
setup_oscillator(OSC_4MHZ);
// ADCON0 = 0x01;
// ADCON1 = 0b10001110;
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_INTERNAL);
//setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_wdt(WDT_2304MS);
//setup_timer_1(T1_DISABLED);
set_tris_b(0x33);
lcd_init();
output_high(PIN_B2);
for (j=0;j<16;j++){
lcd_send_byte(0,0x80|j);
lcd_send_byte(1,init1[j]);
lcd_send_byte(0,0x80|(j+lcd_line_two));
lcd_send_byte(1,init2[j]);
}
#asm
clrwdt
#endasm
changed = 0;
address = 0;
target = read_eeprom(1);
target = target << 8;
target |= read_eeprom(0);
if (target > 30000) target = 7000; //70C
current = 0;
adc_raw = 0;
adc_avg = 0;
#asm
clrwdt
#endasm
buffer[0]=buffer[1]=buffer[2]=buffer[3]=0;
delay_ms(1000);
for (j=0;j<16;j++){
lcd_send_byte(0,0x80|j);
lcd_send_byte(1,gen1[j]);
lcd_send_byte(0,0x80|(j+lcd_line_two));
lcd_send_byte(1,gen2[j]);
}
set_adc_channel(0);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
while (TRUE){
#asm
clrwdt
#endasm
adc_raw = read_adc();
adc_avg = (adc_avg *2 + adc_raw) / 3;
current = getTemp();
pid();
print_temp(1, current);
if (!input(PIN_B0) || !input(PIN_B5)) menu();
if (changed){ //something came via I2C
target = buffer[1];
target = target << 8;
target |= buffer[0];
print_temp(0, target);
changed = 0;
}
//write data into buffer for I2C read
buffer[2] = current & 0x00ff;
buffer[3] = current >> 8;
}
}
slobodno ga koristite kako god zelite :D ... napisan u PICC C kompajleru za 16F819. Prebacio sam ga za PICC posto pravi malo optimalniji kod (jedno 10%) od mikroC-a a i ima podrsku za I2C slave. Imam ja napisanu i software biblioteku za i2c slave ali zahteva da teras pic na mnogo mhz da bi radilo ok .. a i sto bi se cimao sa tim kad ima hw i2c na 819 :)
koga zanima sta radi ...
1. procita iz lokalnog eeproma zadnju snimljenu vrednost za target temperaturu
2. menja target temperaturu na 2 gumba (+ i -)
3. ako se stisnu + i - u isto vreme zapamti trenutnu target temperaturu u eprom
4. ako je target temp nizi od trenutne temperature upali grejac
5. ako je target temp visi od trenutne temperature ugasi grejac
6. slusa kao i2c slave
6.1 na i2c slave adresi 0 i 1 je dvobajtna vrednost target temperature (read/write)
6.2 na i2c slave adresi 2 i 3 je dvobajtna vrednost trenutne temperature (read only) tako da master moze da pita za trenutnu temperaturu ako ga zanima
7. prijazuje na 2x16 display-u obe temperature
to je sve :) ...