/* * geiger.c ... geiger-mueller counter firmware * * Copyright (C) Jiri Pittner * * 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 3 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, see . * * */ //hardware: atmega16 @ 14.7456 mhz // frequency of the high voltage switched power supply (hertz) #define FREQ 33000 //target voltage for the GM tube (volts) #define TARGET_V 505 //threshold voltage for peak detection (millivolts) #define TARGET_V2 4000 #undef debug /*PIN assignment * LCD display: PC0-3=DB4-7 PC4=E PC5=RW PC6=RS or PD4 on atmega8 PC7=light (via NPN bc337 transistor 1k to base and 0R collector resistor - about 100mA) contrast 1k5 to gnd buttons (capacitors 100nF at contacts necessary to prevent spurious edges): PD2 = INT0 - both buttons via 1N4148 PB1 = button left PB0 = button right RESET - 330k na +, 180pF na gnd RX - 220k na gnd PD5 = OC1A = output to gate of IRLZ34N, 4k7 to gnd ADC7 = voltage battery 150k/33k 1n5 blocked ADC6 = high voltage 10M/47k 15nF blocked PD4 = OC1B = output to pwd dac for reference threshold ADC5, AIN1=PB3 = reference voltage PD7 = sound via 1k to PD3(INT1) = interrupt via differentiator */ #include "backward.h" #include #include #include #include #include #include #include //obsolete #include #include #include #include #if defined(at90s2313) || defined(at90s8535) #else #define ATmega #endif #ifdef ATmega #define USR UCSRA #endif #ifndef MCU #define emulate #else #define AVR_assembler #endif #define itoa10(N,S) itoa(N,S,10) #define itoa16(N,S) itoa(N,S,16) void printP (PGM_P string){ char c; c=pgm_read_byte(string); while (c) { loop_until_bit_is_set(USR, UDRE); UDR = c; c=pgm_read_byte(++string); } return; } void putcharx(char c) {loop_until_bit_is_set(USR, UDRE); UDR=c;} void print (char *string){ while (*string) { loop_until_bit_is_set(USR, UDRE); UDR = *string++; } return; } //UART initialize #ifdef ATmega #define UCR UCSRB #define UART_INIT(baud) { \ UBRRH=0; \ UBRRL= (XTAL/baud+15)/16-1; \ UCSRB=(1<>4); lcd_w4bit(rs,x); } void lcd_clear(void) { lcd_wbyte(0,0x01); delay_xs(30000); } void lcd_init(void) { lcd_init4bit(); lcd_wbyte(0,0x28); lcd_wbyte(0,0x08); lcd_clear(); lcd_wbyte(0,0x06); lcd_wbyte(0,0x0c); } void lcd_print(char *t) { while(*t) if(*t=='\n') {++t; lcd_wbyte(0,0xc0);} else lcd_wbyte(1,*t++); } void lcd_print8(char *t) { uint8_t l=0; while(*t) {lcd_wbyte(1,*t++); ++l;} while(l<8) {lcd_wbyte(1,' '); ++l;} } void lcd_cursor(uint8_t r, uint8_t c) { lcd_wbyte(0,0x80+c+(r<<6)); } void printfreq(char *text, uint16_t freq) { uint8_t i; char *p = text+5; for(i=0; i<5; ++i) { *p-- = freq ? freq%10 + '0' : ' ' ; freq /= 10; if(i==1) *p-- = '.'; } strcpy(text+6,"Hz"); return; } void printpermin(char *text, uint16_t freq) { uint8_t i; char *p = text+4; for(i=0; i<5; ++i) { *p-- = freq ? freq%10 + '0' : ' ' ; freq /= 10; } strcpy(text+5,"rpm"); return; } #define BAUD 115200 #define CK__(X) CK##X #define CK_(X) CK__(X) uint16_t adcread(uint8_t mux, uint8_t i) { uint16_t v; uint16_t v0; //enable A/D converter in single conversion mode v=0; while(i--) { ADMUX= mux & 0x0f; ADCSRA= (1<>(11+ADCREP)); } uint16_t refvoltage(void) //in millivolts, direct { uint32_t v; v = adcread(5,1<>(10+ADCREP)); } uint8_t batvoltage(void) { uint32_t v; v = adcread(7,1<>(12+ADCREP)); } volatile uint8_t autostop=0; INTERRUPT(SIG_OUTPUT_COMPARE2) { if(autostop) {TCCR2=0; cbi(PORTD,PD7); cbi(TIMSK,OCIE2);} } void beep(uint16_t freq) { if(freq>1) //beep { sbi(PORTD,PD7); sbi(DDRD,PD7); TCNT2=0; OCR2= XTAL/freq/1024; TCCR2 = (1<0; --i) { --p; if(i==6) *p='.'; else { *p = ((usvh!=0||i>=5)? ('0' + usvh%10) : ' '); usvh /= 10; } } } void itoa10_32(uint32_t n, char *p) { char tmp[16]; char *q=tmp; uint8_t i; for(i=11; i>0; --i) { *q++ = '0' + n%10 ; n /= 10; if(n==0) {*q=0; break;} } while(q>tmp) *p++ = *--q; *p=0; } void printbat(uint16_t v, char *p) { p+=8; *p=0; *--p = 'V'; uint8_t i; for(i=7; i>0; --i) { --p; if(i==6) *p='.'; else { *p = ((v!=0||i>=5)? ('0' + v%10) : ' '); v /= 10; } } } void printtime(uint32_t cs, char *text, char *text2) { text2[8]=0; text2[7]='s'; cs/=100; text2[6]='0'+ cs%10; cs/=10; text2[5]='0'+ cs%6; cs/=6; text2[4]=' '; text2[3]='m'; text2[2]='0'+ cs%10; cs/=10; text2[1]='0'+ cs%6; cs/=6; text2[0]=' '; uint8_t h = cs%24; cs/=24; text[8]=0; text[7]='h'; text[6]='0'+ h%10; h/=10; text[5]='0'+ h; text[4]=' '; text[3]='d'; text[2]='0'+ cs%10; cs/=10; text[1]=cs ? '0'+ cs%10 : ' '; cs/=10; text[0]=cs ? '0'+ cs%10 : ' '; } static const char modetype[4]="slc"; int main(void) { uint8_t prompt=1; uint8_t autoprint = 0; uint32_t usvh=0; uint32_t usvhold=0; uint16_t ii; cbi(PORTD,PD5); sbi(DDRD,PD5);//oc1a cbi(PORTD,PD4); sbi(DDRD,PD4);//oc1b UART_INIT(BAUD); printP(PSTR("Reset!\n> ")); sbi(PORTC,PC7); cbi(DDRC,PC7); light=0; //global interrupt activate sbi(SREG,7); //allow button interrupts and pullup cbi(DDRD,PD2); sbi(PORTD,PD2); cbi(DDRB,PB0); sbi(PORTB,PB0); cbi(DDRB,PB1); sbi(PORTB,PB1); cbi(MCUCR,ISC00); sbi(MCUCR,ISC01); sbi(GIMSK,INT0); //allow geiger interrupts, no pullup ACSR = 1< TARGET_V+1 && duty > 1 && v>vold) {duty-=1;} if(v < TARGET_V-1 && duty < XTAL/FREQ/4 && v TARGET_V+20 && duty > 2) {duty -= 2;} //if(v < TARGET_V-30 && duty < XTAL/FREQ/4) {duty+=1;} if(v > TARGET_V+40) {TCNT1=0; duty=1;} OCR1A=duty; vold=v; //check reference voltage generator and adjust duty uint16_t v2=refvoltage(); #ifdef debug if((ii&1023)==0) { printP(PSTR("REF V=")); itoa10(v2,text); print(text); printP(PSTR("\n")); } #endif if(v2 > TARGET_V2+1 && duty2 > 1 && v2>vold2) {duty2 -=1;} if(v2 < TARGET_V2-1 && duty2 < XTAL/FREQ-1 && v22) {printP(PSTR("Inappropriate mode.")); break;} printP(PSTR("Radiation(")); putcharx(modetype[dispmode]); printP(PSTR(") = ")); printusvh(usvh,text); print(text); printP(PSTR(" uSv/h")); } break; case 'd': printusvh(geigertot1/27,text); printP(PSTR("Dosis = ")); print(text); printP(PSTR(" uSv")); break; case 't': { char text2[9]; printtime(centiseconds,text,text2); printP(PSTR("Time = ")); print(text); print(text2); } break; case 'c': printP(PSTR("Counts = ")); itoa10_32(geigertot1,text); print(text); printP(PSTR(" ")); itoa10_32(geigertot2,text); print(text); break; case 'v': printP(PSTR("Geiger voltage = ")); itoa10(v,text); print(text); printP(PSTR("V")); break; case 'r': printP(PSTR("Reference = ")); itoa10(v2,text); print(text); printP(PSTR("mV")); break; case 'b': printbat(batvoltage(),text); printP(PSTR("Battery = ")); print(text); break; case 'l': light ^= (1< ")); inuartlen=0; uartline=0; } //LCD print if((ii&127)==0||freshcleared) { if(newstart) { geigercount=0; geigertot1=0; geigertot2=0; newstart=0; timestamp=centiseconds; } switch(dispmode){ default: case 0: if(freshcleared || geigercount * (centiseconds-timestamp) > 100000 ) { usvh = calcusvh(geigercount,centiseconds-timestamp); timestamp = centiseconds; geigercount = 0 ; } printusvh(usvh,text); lcd_cursor(0,0); lcd_print8(text); lcd_cursor(1,0); lcd_print8("s uSv/h"); break; case 1: if(freshcleared || geigercount * (centiseconds-timestamp) > 1000000 ) { usvh = calcusvh(geigercount,centiseconds-timestamp); timestamp = centiseconds; geigercount = 0 ; } printusvh(usvh,text); lcd_cursor(0,0); lcd_print8(text); lcd_cursor(1,0); lcd_print8("l uSv/h"); break; case 2: usvh = calcusvh(geigertot1,centiseconds); printusvh(usvh,text); lcd_cursor(0,0); lcd_print8(text); lcd_cursor(1,0); lcd_print8("c uSv/h"); break; case 3: printusvh(geigertot1/27,text); lcd_cursor(0,0); lcd_print8(text); lcd_cursor(1,0); lcd_print8(" uSv"); break; case 4: itoa10_32(geigertot1,text); lcd_cursor(0,0); lcd_print8(text); itoa10_32(geigertot2,text); lcd_cursor(1,0); lcd_print8(text); break; case 5: { char text2[9]; printtime(centiseconds,text,text2); lcd_cursor(0,0); lcd_print8(text); lcd_cursor(1,0); lcd_print8(text2); } break; case 6: lcd_cursor(0,0); lcd_print8("Reset"); lcd_cursor(1,0); lcd_print8("Tot. Dose"); break; case 7: lcd_cursor(0,0); lcd_print8("Sound"); lcd_cursor(1,0); lcd_print8(dotick?"On":"Off"); break; case 8: lcd_cursor(0,0); lcd_print8("Battery"); lcd_cursor(1,0); printbat(batvoltage(),text); lcd_print8(text); break; } freshcleared=0; } }//while }