#define signal(del) BUZZERPORT |= (1<<BUZZERPIN); _delay_ms(del); BUZZERPORT &= ~(1<<BUZZERPIN)
#define setCursor(pos, row) lcdSendByte(0x80|(0x40*row)|(pos), 0)
#define displayOn() PORTA |= (1<<LCDPOWER); _delay_ms(50); displayInit()
#define displayOff() PORTA &= ~(1<<LCDPOWER);
#define lcd_print(str) _lcd_print_P((const char*)(str))
#define DEC_TO_BCD(d) ((uint8_t)((((d) / 10u) << 4u) | ((d) % 10u)))
#define BCD_TO_DEC(b) ((uint8_t)(((((b) >> 4u) & 0x0Fu) * 10u) + ((b) & 0x0Fu)))
#define isFrontButton (pastButton < (PIND & (1<<ENCBUTTON)))
#define isFrontChSet (pastChSet < (PIND & (1<<CHANNEL_SET)))
#define lcdClear() lcdSendByte(0x01, 0); _delay_ms(2)
#define WDTFCHECK() \
do { \
if (WDT_flag) { \
uniBoolFlag &= ~(1<<3); \
return; \
} \
} while(0)
#define BUZZERPORT PORTB
#define BUZZERPIN PB6
#define COMPPLUS PB0
#define COMPMINUS PB1
#define SDA PB7
#define SCL PB5
#define ENCBUTTON PD2
#define MOSFET_A PD3
#define CHANNEL_A_PIN PD4
#define CHANNEL_B_PIN PD5
#define ENC_A PB4
#define ENC_B PB3
#define CHANNEL_SET PD6
#define MOSFET_B PB2
#define SELFLOCK PA0
#define LCDPOWER PA1
#define BIT_REGSET 0
#define BIT_READWRITE 1
#define BIT_ENABLE 2
#define BIT_BACKLIGHT 3
/[I]reserved or unused[/I]/
#define UART_RX PD0
#define UART_TX PD1
/**/
//display strings
const char STR_CH_A[] PROGMEM = "KAH A";
const char STR_CH_B[] PROGMEM = "KAH B";
const char STR_SET[] PROGMEM = "HACTPO\001KA";
const char STR_CALIBRATE[] = "KA\000\0006POBKA";
//#define STR_RESET_H "C6POC 4ERE3 8 C."
//#define STR_RESET_L "OTMEHA - \002M\001 OK!"
const char STR_SETTIME[] PROGMEM = ("HACTPO\001KA BPEMEH\001");
const char STR_UPTIME[] PROGMEM = "UPTIME x8 CEK";
const char STR_CALIBRATE_MIN[] PROGMEM = "M\001H\001MYM KOPMA MC";
const char STR_CALIBRATE_STEP[] PROGMEM = "\007AG ME\002DY 0\0011";
#define bmsstate (uniBoolFlag >> 6)
#define isActive ((uniBoolFlag >> 5) & 1)
#define currentChannel ((uniBoolFlag >> 4) & 1)
#define WDT_flag ((uniBoolFlag >> 3) & 1)
#define pastButton ((uniBoolFlag >> 2) & 1)
#define pastChSet ((uniBoolFlag >> 1) & 1)
#define isMinutes (uniBoolFlag & 1)
#define F_CPUdiv1000 8000UL
#define F_CPUdiv1000000 8
#define NONE 0
#define CW 1
#define HOLD_CW 2
#define CCW 3
#define HOLD_CCW 4
uint8_t pastEncoderState;
uint8_t displayBuffer[16];
uint8_t timeHMS[3];
uint16_t uptime;
uint8_t timeBuffer[2][4];
uint8_t lasttimers[2];
uint8_t calibrateMin[2];
uint8_t calibrateStep[2];
uint8_t cursor;
uint8_t uniBoolFlag;
void _lcd_print_P(const char* literal){
uint8_t ch;
while((ch = pgm_read_byte((uint8_t*)literal++))){
lcdSendByte(ch, 1);
}
}
uint8_t div100(uint8_t num){
if(num < 100) return 0;
if(num < 200) return 1;
return 2;
}
void utoa(uint16_t num, char* bfr){
//bfr[0] = num/10000+48;
// bfr[1] = num%10000/1000+48;
bfr[0] = (num*164)>>14+48;//div100(num)+48;
bfr[1] = (num%100*205)>>11+48; //((num-bfr[0]*2600)>>8)+48;
bfr[2] = (num-bfr[1]*10)+48;
}
void _delay_ms(uint16_t time){
uint32_t i = (F_CPUdiv1000)*time;
do{asm volatile("nop");}while(--i);
}
/*void _delay_ms_16bit(uint16_t time){
uint16_t i = (F_CPUdiv1000)*time;
do{asm volatile("nop");asm volatile("nop");}while(--i);
}*/
void _delay_us(uint8_t time){
uint8_t i = (F_CPUdiv1000000)*time;
do{asm volatile("nop");}while(--i);
}
void usiClock(){
USICR |= (1<<USITC);
_delay_ms(5);
USICR |= (1<<USITC);
_delay_ms(5);
}
uint8_t encmonitoring(){
uint8_t encState = (PINB&0B00011000)>>3;
if(encState==pastEncoderState) return NONE;
asm volatile("wdr");
uint8_t result = (((encState&1)^(pastEncoderState>>1)<<1)|1)+((PIND&(1<<ENCBUTTON))>>ENCBUTTON);
pastEncoderState = encState;
return result;
}
void usi_start() {
PORTB |= (1<<SDA)|(1<<SCL);
_delay_us(5);
PORTB &= ~(1<<SDA);
_delay_us(5);
}
void usi_stop() {
PORTB &= ~((1<<SDA)|(1<<SCL));
_delay_us(5);
PORTB |= (1<<SCL);
_delay_us(5);
PORTB |= (1<<SDA);
_delay_us(5);
}
void usi_send(uint8_t data) {
USIDR = data;
USISR = (1<<USIOIF)|(0x0F);
while((USISR & (1<<USIOIF)) == 0) {
usiClock();
}
usiClock();
DDRB &= ~(1 << SDA);
USISR = (1 << USIOIF) | (0x0E);
usiClock();
DDRB |= (1 << SDA);
}
uint8_t usi_read(uint8_t isAck) {
uint8_t result;
DDRB &= ~(1<<SDA);
USISR = (1<<USIOIF)|(0x0F);
while((USISR & (1<<USIOIF)) == 0) {
usiClock();
}
result = USIDR;
USIDR = 0xFF * isAck;
USISR = (1 << USIOIF) | (0x0E);
usiClock();
USIDR = 0xff;
return result;
}
[B]attribute[/B]((noinline))
void lcdSendNibble(uint8_t _byte, uint8_t isData) {
usi_send(0x27<<1);
usi_send((_byte)|(isData<<BIT_REGSET)|(1<<BIT_ENABLE));
_delay_us(10);
usi_send((_byte)|(isData<<BIT_REGSET));
_delay_us(100);
return;
}
void lcdSendByte(uint8_t _byte, uint8_t isData) {
usi_send(0x27<<1);
lcdSendNibble((_byte>>4), isData);
lcdSendNibble(_byte&0b1111, isData);
}
void internalTimeActualize() {
usi_start();
usi_send(0xd0);
usi_send(0);
usi_start();
usi_send(0xd1);
timeHMS[0] = BCD_TO_DEC(usi_read(true));
timeHMS[1] = BCD_TO_DEC(usi_read(true));
timeHMS[2] = BCD_TO_DEC(usi_read(false));
usi_stop();
}
void externalTimeActualize() {
usi_start();
usi_send(0xd0);
usi_send(0);
usi_send(DEC_TO_BCD(timeHMS[0]));
usi_send(DEC_TO_BCD(timeHMS[1]));
usi_send(DEC_TO_BCD(timeHMS[2]));
usi_stop();
}
void createChar(uint8_t* array, uint8_t posit) {
usi_start();
usi_send(0x27<<1);
lcdSendByte(posit|0x40, 0);
for(uint8_t i = 0; i<8; i++) {
lcdSendByte(array[i], 1);
}
usi_stop();
}
void lcd_createAllChars() {
byte smile[8] =
{
B00000,
B00110,
B01010,
B01010,
B01010,
B01010,
B11010,
B00000,
};
createChar(smile, 0);
uint8_t smile1[] =
{
B00000,
B10001,
B10001,
B10011,
B10101,
B11001,
B10001,
B00000,
};
createChar(smile1, 1);
uint8_t smile2[] =
{
B00000,
B10101,
B10101,
B01110,
B01110,
B10101,
B10101,
B00000,
};
createChar(smile, 2);
uint8_t smile3[8];
for(int8_t i=3; i>=0; i--){
smile3[i<<1] = 63;
smile3[i<<1+1] = 63;
createChar(smile3, 3+i);
}
uint8_t smile4[8] = {0x00, 0x15, 0x15, 0x15, 0x15, 0x1F};
createChar(smile4, 7);
}
void eepromLoad(uint8_t data, uint8_t address) {
while(EECR & (1<<EEPE));
EEAR = address;
EEDR = data;
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
}
uint8_t eepromRead(uint8_t address) {
while(EECR & (1<<EEPE));
EEAR = address;
EECR |= (1<<EERE);
return EEDR;
}
void feed(uint8_t channel) {
uint8_t msdiv20 = calibrateMin[channel] + (calibrateStep[channel] * (timeBuffer[channel][lasttimers[channel]] & 7));
do{
PORTD |= (1 << (PD4 + channel));
_delay_ms(1);
PORTD ^= (1 << (PD4 + channel));
_delay_ms(19);
}while(--msdiv20);
msdiv20 = 50;
do{
PORTD |= (1 << (PD4 + channel));
_delay_ms(2);
PORTD ^= (1 << (PD4 + channel));
_delay_ms(18);
}while(--msdiv20);
}
ISR(WDT_vect) {
//sei();
signal(500);
if(isActive) {
uint8_t i = 8;
do{
eepromLoad(timeBuffer[i>>2][i&3], i);
}while(--i);
eepromLoad(8, calibrateMin);
eepromLoad(9, calibrateStep);
displayOff();
uniBoolFlag &= ~(1<<5);
};
uptime++;
internalTimeActualize();
if((timeBuffer[0][lasttimers[0]] == timeHMS[2]) && (timeHMS[1] == 0) && (timeHMS[0] < 8)) {
PORTD |= (1<<MOSFET_A);
feed(0);
PORTD &= ~(1<<MOSFET_A);
};
if((timeBuffer[1][lasttimers[1]] == timeHMS[2]) && (timeHMS[1] == 0) && (timeHMS[0] < 8)) {
PORTB |= (1<<MOSFET_B);
feed(1);
PORTB &= ~(1<<MOSFET_B);
};
if(ACSR & (1<<ACO)) {
uniBoolFlag += (1<<6);;
} else {
uniBoolFlag &= ~(3<<6);
};
if(bmsstate >= 3) {
PORTA |= (1<<SELFLOCK);
};
}
void displayUpdate() {
uint8_t i = 4;
do{
displayBuffer[i*4] = (timeBuffer[currentChannel][i] >> 3) / 10 + '0';
displayBuffer[i*4+1] = (timeBuffer[currentChannel][i] >> 3) % 10 + '0';
displayBuffer[i*4+2] = (timeBuffer[currentChannel][i] >> 3) >> 1 + 3; //не перевод в строчку,с места 3 и далее в памяти дисплея - кастомные символы для градаций
displayBuffer[i*4+3] = ' ';
}while(--i);
setCursor(0, 0);
for(uint8_t i=0; i<16; i++) {
lcdSendByte(i, 1);
}
}
void displayInit() {
_delay_ms(50);
for(uint8_t i = 0; i < 3; i++){
lcdSendNibble(0x03, 0);
_delay_ms(5);
};
lcdSendNibble(0x02, 0);
_delay_us(50);
lcdSendByte(0x28, 0);
lcdSendByte(0x06, 0);
}
void menuDriver(uint8_t& incnum, uint8_t incvalue = 1){
setCursor(11, 1);
lcd_print(currentChannel ? STR_CH_B: STR_CH_A);
lcdSendByte(0x02, 0);
WDTFCHECK();
switch(encmonitoring()) {
case CW:
incnum+= incvalue;
break;
case CCW:
incnum-= incvalue;
break;
case HOLD_CW:
calibrate();
default:
break;
}
displayUpdate();
setCursor(cursor * 4, 0);
if(PIND & (1<<CHANNEL_SET)) {
uniBoolFlag ^= (1<<4);
}
if(!(PIND & (1<<ENCBUTTON))) uniBoolFlag &= ~(1<<2);
}
void calibrate() {
mainmenu:
setCursor(0,0);
lcd_print("ЧАС АПТ МИН \007АG"); //char-array
setCursor(0,1);
lcd_print(STR_CALIBRATE);
while(1) {
menuDriver(cursor);
if(isFrontButton) {
switch(cursor) {
case 0:
setCursor(0, 1);
lcd_print(STR_SETTIME);
setCursor(0, 0);
uniBoolFlag &= ~1;
while(1) {
menuDriver(timeHMS[1+isMinutes]);
if(isFrontButton) {
uniBoolFlag |= (1<<2);
if(isMinutes) {
externalTimeActualize();
goto mainmenu;
}
uniBoolFlag |= 1;
}
}
break;
/*case 1:
setCursor(0,0);
char bfrstr[5];
utoa(uptime, bfrstr, 10);
lcd_print(bfrstr); //char-array
setCursor(0,1);
lcd_print(STR_UPTIME);
if(!(PIND & (1<<ENCBUTTON))) uniBoolFlag &= ~(1<<2);
while(1) {
if(isFrontButton) {
uniBoolFlag |= (1<<2);
goto mainmenu;
}
}
break;
*/
case 2:
calibrateUnit2And3(0);
break;
case 3:
calibrateUnit2And3(1);
}
}
}
}
void calibrateUnit2And3(uint8_t isStep) {
setCursor(0,0);
char bfrstr[3];
utoa(calibrateMin[currentChannel], bfrstr);
lcd_print(bfrstr); //char-array
setCursor(0,1);
lcd_print(STR_CALIBRATE_MIN);
uint8_t* calibrateX = isStep?calibrateStep:calibrateMin;
setCursor(0,0);
while(1) {
switch(encmonitoring()) {
case CW:
calibrateMin[currentChannel]++;
utoa(calibrateX[currentChannel], bfrstr);
lcd_print(bfrstr);
break;
case CCW:
calibrateMin[currentChannel]--;
utoa(calibrateX[currentChannel], bfrstr);
lcd_print(bfrstr);
break;
case HOLD_CW:
return;
default:
break;
}
if(!(PIND & (1<<ENCBUTTON))) {
uniBoolFlag &= ~(1<<2);
}
if(isFrontButton) {
uniBoolFlag |= (1<<2);
feed(currentChannel);
}
}
}
ISR(INT0_vect) {
uniBoolFlag |= (1<<5);
displayOn();
mainmenu:
while(1) {
menuDriver(cursor);
if(!(PIND & (1<<ENCBUTTON))) uniBoolFlag &= ~(1<<2);
if(isFrontButton) {
uniBoolFlag |= (1<<2);
menuDriver(timeBuffer[currentChannel][cursor], 8);
if(isFrontButton) {
uniBoolFlag |= (1<<2);
menuDriver(timeBuffer[currentChannel][cursor]);
if(isFrontButton) {
uniBoolFlag |= (1<<2);
goto mainmenu;
}
}
}
}
}
int main() {
DDRB |= ((1<<BUZZERPIN)|(1<<SDA)|(1<<SCL)|(1<<MOSFET_B));
DDRD |= ((1<<MOSFET_A)|(1<<CHANNEL_A_PIN)|(1<<CHANNEL_B_PIN));
DDRA |= ((1<<SELFLOCK)|(1<<LCDPOWER));
signal(100);
if(MCUSR){
signal(200);
}
USICR |= 0B00100010;
asm volatile("wdr");
MCUSR = 0;
WDTCSR |= (1<<WDCE)|(1<<WDE);
WDTCSR |= (1<<WDIE)|(1<<WDP0)|(1<<WDP3);
sei();
MCUCR = 0b00110011;
//GIMSK |= (1<<INT0);
lable:
asm volatile("nop");
goto lable;
}