Created
June 13, 2014 01:05
-
-
Save piotrmaslanka/8b23d7b59116b2ebf9c5 to your computer and use it in GitHub Desktop.
[Atmel AVR] Software for my DIY home alarm controller. Superseded by a ladder-logic PLC solution. Contains a very nice UART/MODBUS library though.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define F_CPU 1843200 | |
#include "avr/interrupt.h" | |
#include "avr/wdt.h" | |
#include "pins.h" | |
#include "uart.h" | |
#define SIGNAL_LENGTH 4 | |
#define ALARM_LENGTH 0x04EC | |
#define VB_ARMED 0x7F | |
#define VB_UNARMED 0x01 | |
unsigned char bAlarmMask, bAlarmEnabled, bSiren, bDebugStatus = 0, bPresenceSuspend = 0; | |
void rearm(unsigned char newMask) | |
{ | |
bAlarmEnabled = 0; | |
bAlarmMask = (newMask | VB_UNARMED) & VB_ARMED; | |
} | |
void boot() | |
{ | |
rearm(VB_UNARMED); | |
pins_init(); | |
uart_init(); | |
wdt_enable(WDTO_60MS); | |
sei(); | |
} | |
void loop() | |
{ | |
unsigned char presence = 0; // --------------- do presence | |
for(int i=0; i<7; i++) | |
if (baTrigger[i] >= SIGNAL_LENGTH) presence |= 1 << i; | |
if ((presence & bAlarmMask) > 0) // -------------- check alarm | |
{ | |
cli(); iTimer = 0; sei(); | |
bAlarmEnabled = 1; | |
} | |
// -------------------- alarm disabler | |
if ((bAlarmEnabled == 1) && (iTimer > ALARM_LENGTH)) bAlarmEnabled = 0; | |
// -------------- arm-via-casette | |
if (baTrigger[7] == SIGNAL_LENGTH) | |
{ | |
cli(); baTrigger[7]++; sei(); | |
if (bAlarmMask == VB_UNARMED) rearm(VB_ARMED); | |
else rearm(VB_UNARMED); | |
} | |
// -------------- arm led blinker | |
if (bAlarmMask == VB_ARMED) | |
{ | |
pins_out(PINS_ARMLED, 1); | |
} | |
else if (bAlarmMask == VB_UNARMED) | |
{ | |
pins_out(PINS_ARMLED, 0); | |
} | |
else | |
{ | |
if ((iTimer & 16) == 16) pins_out(PINS_ARMLED, 1); | |
else pins_out(PINS_ARMLED, 0); | |
} | |
// ---------------------- siren | |
uint8_t siren_temp = 0; | |
siren_temp |= bSiren; | |
siren_temp |= bAlarmEnabled; | |
pins_out(PINS_SIREN, siren_temp); | |
// ---------------------- suspend stopper | |
bPresenceSuspend |= presence; | |
wdt_reset(); | |
} | |
int main() | |
{ | |
boot(); | |
for (;;) loop(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define SIGNAL_LENGTH 5 | |
#define ALARM_LENGTH 0x04EC | |
#define VB_ARMED 0x7F | |
#define VB_UNARMED 0x01 | |
unsigned char bAlarmMask, bAlarmEnabled, bSiren, bPresenceSuspend, bDebugStatus; | |
void rearm(unsigned char newMask); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "uart.h" | |
const unsigned int CRC_LOOKUP_TABLE[256] = | |
{ | |
0x0000, | |
0xc0c1, | |
0xc181, | |
0x140, | |
0xc301, | |
0x3c0, | |
0x280, | |
0xc241, | |
0xc601, | |
0x6c0, | |
0x780, | |
0xc741, | |
0x500, | |
0xc5c1, | |
0xc481, | |
0x440, | |
0xcc01, | |
0xcc0, | |
0xd80, | |
0xcd41, | |
0xf00, | |
0xcfc1, | |
0xce81, | |
0xe40, | |
0xa00, | |
0xcac1, | |
0xcb81, | |
0xb40, | |
0xc901, | |
0x9c0, | |
0x880, | |
0xc841, | |
0xd801, | |
0x18c0, | |
0x1980, | |
0xd941, | |
0x1b00, | |
0xdbc1, | |
0xda81, | |
0x1a40, | |
0x1e00, | |
0xdec1, | |
0xdf81, | |
0x1f40, | |
0xdd01, | |
0x1dc0, | |
0x1c80, | |
0xdc41, | |
0x1400, | |
0xd4c1, | |
0xd581, | |
0x1540, | |
0xd701, | |
0x17c0, | |
0x1680, | |
0xd641, | |
0xd201, | |
0x12c0, | |
0x1380, | |
0xd341, | |
0x1100, | |
0xd1c1, | |
0xd081, | |
0x1040, | |
0xf001, | |
0x30c0, | |
0x3180, | |
0xf141, | |
0x3300, | |
0xf3c1, | |
0xf281, | |
0x3240, | |
0x3600, | |
0xf6c1, | |
0xf781, | |
0x3740, | |
0xf501, | |
0x35c0, | |
0x3480, | |
0xf441, | |
0x3c00, | |
0xfcc1, | |
0xfd81, | |
0x3d40, | |
0xff01, | |
0x3fc0, | |
0x3e80, | |
0xfe41, | |
0xfa01, | |
0x3ac0, | |
0x3b80, | |
0xfb41, | |
0x3900, | |
0xf9c1, | |
0xf881, | |
0x3840, | |
0x2800, | |
0xe8c1, | |
0xe981, | |
0x2940, | |
0xeb01, | |
0x2bc0, | |
0x2a80, | |
0xea41, | |
0xee01, | |
0x2ec0, | |
0x2f80, | |
0xef41, | |
0x2d00, | |
0xedc1, | |
0xec81, | |
0x2c40, | |
0xe401, | |
0x24c0, | |
0x2580, | |
0xe541, | |
0x2700, | |
0xe7c1, | |
0xe681, | |
0x2640, | |
0x2200, | |
0xe2c1, | |
0xe381, | |
0x2340, | |
0xe101, | |
0x21c0, | |
0x2080, | |
0xe041, | |
0xa001, | |
0x60c0, | |
0x6180, | |
0xa141, | |
0x6300, | |
0xa3c1, | |
0xa281, | |
0x6240, | |
0x6600, | |
0xa6c1, | |
0xa781, | |
0x6740, | |
0xa501, | |
0x65c0, | |
0x6480, | |
0xa441, | |
0x6c00, | |
0xacc1, | |
0xad81, | |
0x6d40, | |
0xaf01, | |
0x6fc0, | |
0x6e80, | |
0xae41, | |
0xaa01, | |
0x6ac0, | |
0x6b80, | |
0xab41, | |
0x6900, | |
0xa9c1, | |
0xa881, | |
0x6840, | |
0x7800, | |
0xb8c1, | |
0xb981, | |
0x7940, | |
0xbb01, | |
0x7bc0, | |
0x7a80, | |
0xba41, | |
0xbe01, | |
0x7ec0, | |
0x7f80, | |
0xbf41, | |
0x7d00, | |
0xbdc1, | |
0xbc81, | |
0x7c40, | |
0xb401, | |
0x74c0, | |
0x7580, | |
0xb541, | |
0x7700, | |
0xb7c1, | |
0xb681, | |
0x7640, | |
0x7200, | |
0xb2c1, | |
0xb381, | |
0x7340, | |
0xb101, | |
0x71c0, | |
0x7080, | |
0xb041, | |
0x5000, | |
0x90c1, | |
0x9181, | |
0x5140, | |
0x9301, | |
0x53c0, | |
0x5280, | |
0x9241, | |
0x9601, | |
0x56c0, | |
0x5780, | |
0x9741, | |
0x5500, | |
0x95c1, | |
0x9481, | |
0x5440, | |
0x9c01, | |
0x5cc0, | |
0x5d80, | |
0x9d41, | |
0x5f00, | |
0x9fc1, | |
0x9e81, | |
0x5e40, | |
0x5a00, | |
0x9ac1, | |
0x9b81, | |
0x5b40, | |
0x9901, | |
0x59c0, | |
0x5880, | |
0x9841, | |
0x8801, | |
0x48c0, | |
0x4980, | |
0x8941, | |
0x4b00, | |
0x8bc1, | |
0x8a81, | |
0x4a40, | |
0x4e00, | |
0x8ec1, | |
0x8f81, | |
0x4f40, | |
0x8d01, | |
0x4dc0, | |
0x4c80, | |
0x8c41, | |
0x4400, | |
0x84c1, | |
0x8581, | |
0x4540, | |
0x8701, | |
0x47c0, | |
0x4680, | |
0x8641, | |
0x8201, | |
0x42c0, | |
0x4380, | |
0x8341, | |
0x4100, | |
0x81c1, | |
0x8081, | |
0x4040 | |
}; | |
void crc_calculate() | |
{ | |
mbCRCH = 0xFF; | |
mbCRCL = 0xFF; | |
for(unsigned char i = 0; i < buffer_length; i++) | |
{ | |
unsigned char value = buffer[i]; | |
unsigned int factor = CRC_LOOKUP_TABLE[value ^ mbCRCL]; | |
mbCRCL = mbCRCH ^ (unsigned char)(factor & 0xFF); | |
mbCRCH = (unsigned char)(factor >> 8); | |
} | |
unsigned char temp = mbCRCH; | |
mbCRCH = mbCRCL; | |
mbCRCL = temp; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void crc_calculate(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "avr/io.h" | |
#include "avr/interrupt.h" | |
#include "uart.h" | |
#define PINS_SIREN 1 | |
#define PINS_ARMLED 2 | |
uint16_t iTimer; | |
uint8_t baTrigger[8]; | |
uint8_t pins_collect() | |
{ | |
uint8_t c, d; | |
c = PINC; | |
d = PIND; | |
return (((c & 0xFC) + (d >> 6)) ^ 128); | |
} | |
SIGNAL (SIG_OVERFLOW0) | |
{ | |
iTimer++; | |
uint8_t pins; | |
pins = pins_collect(); | |
for (uint8_t i = 0; i < 8; i++) | |
if (((1 << i) & pins) > 0) baTrigger[i] = baTrigger[i] + 1; | |
else baTrigger[i] = 0; | |
if (bStatus == UART_TRANSMITTING) // If the device spends too much time on transmitting... | |
if ((iTimer - iTransmissionTimer) > 2) // it is invalid - reset transmission, set to listen | |
uart_switch_receive(); | |
} | |
void pins_out(uint8_t what, uint8_t status) | |
{ | |
status = 1 - status; // remember - outputs are negated | |
// by output board design | |
if (what == PINS_SIREN) | |
{ | |
if (status == 0) PORTD &= ~8; | |
else if (status == 1) PORTD |= 8; | |
} | |
else if (what == PINS_ARMLED) | |
{ | |
if (status == 0) PORTD &= ~4; | |
else if (status == 1) PORTD |= 4; | |
} | |
} | |
void pins_init() | |
{ | |
DDRA = 0xFF; | |
DDRB = 0xFF; // PORTA, PORTB unused - outputs | |
DDRC = 0x03; | |
DDRD = 0x3C; | |
pins_out(PINS_SIREN, 0); | |
pins_out(PINS_ARMLED, 0); | |
TCCR0 = (1<<CS02)|(0<<CS01)|(1<<CS00); // Prescaler = 1024 | |
TIMSK = (1 << TOIE0); // Interrupt on overflow | |
// will happen at 7,03 Hz | |
for(uint8_t i=0; i<8; i++) baTrigger[i] = 0; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define PINS_SIREN 1 | |
#define PINS_ARMLED 2 | |
extern unsigned char baTrigger[8]; | |
extern unsigned int iTimer; | |
void pins_out(unsigned char what, unsigned char status); | |
void pins_init(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Alarm.h" | |
#include "uart.h" | |
unsigned int modbus_read_holding(unsigned int port) | |
{ | |
mbhStatus = MODBUS_HANDLE_OK; | |
switch (port) | |
{ | |
case 0x0000: | |
return (bAlarmEnabled << 8) + bPresenceSuspend; | |
case 0x0001: | |
return bAlarmMask; | |
case 0x0002: | |
return bSiren; | |
case 0x0003: | |
return bDebugStatus; | |
default: | |
mbhStatus = MODBUS_HANDLE_ERR; | |
} | |
return 0; | |
} | |
unsigned int modbus_write_holding(unsigned int port, unsigned int value) | |
{ | |
mbhStatus = MODBUS_HANDLE_OK; | |
switch (port) | |
{ | |
case 0x0000: | |
bPresenceSuspend = (unsigned char)(value & 0xFF); | |
return bPresenceSuspend; | |
case 0x0001: | |
rearm((unsigned char)(value & 0xFF)); | |
return bAlarmMask; | |
case 0x0002: | |
bSiren = (unsigned char)(value & 0xFF); | |
return bSiren; | |
case 0x0003: | |
bDebugStatus = (unsigned char)(value & 0xFF); | |
return bDebugStatus; | |
default: | |
mbhStatus = MODBUS_HANDLE_ERR; | |
} | |
return 0; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unsigned int modbus_read_holding(unsigned int port); | |
unsigned int modbus_write_holding(unsigned int port, unsigned int value); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "avr/io.h" | |
#include "avr/interrupt.h" | |
uint16_t timer_timer; | |
SIGNAL (SIG_OVERFLOW0) | |
{ | |
timer_timer++; | |
} | |
void timer_init() | |
{ | |
TCCR0 = (1<<CS02)|(0<<CS01)|(1<<CS00); // equals to 0x05 | |
TIMSK = (1 << TOIE0); // equals to 0x01 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void timer_init(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "avr/io.h" | |
#include "avr/interrupt.h" | |
#include "crc.h" | |
#include "pins.h" // for iTimer | |
#include "registers.h" // MODBUS Responder | |
#define ADDRESS 0x0A | |
#define MAXREGISTER 3 | |
#define SS_ADDRESS 1 | |
#define SS_COMMAND 2 | |
#define SS_REGISTER_H_RW 3 | |
#define SS_REGISTER_L_RW 4 | |
#define SS_VALUE_H_W 5 | |
#define SS_VALUE_L_W 6 | |
#define SS_AMOUNT_H_R 7 | |
#define SS_AMOUNT_L_R 8 | |
#define SS_CRC_H 9 | |
#define SS_CRC_L 10 | |
#define MC_READ 0x03 | |
#define MC_WRITE 0x06 | |
#define MODBUS_HANDLE_OK 0 | |
#define MODBUS_HANDLE_ERR 1 | |
#define UART_TRANSMITTING 0 | |
#define UART_RECEIVING 1 | |
unsigned char bStatus; | |
unsigned char bScanStatus; | |
unsigned int iTransmissionTimer; | |
// ----- modbus values | |
unsigned char mbCommand; | |
unsigned char mbRegisterL; | |
unsigned char mbValueL; | |
unsigned char mbAmountL; | |
unsigned char mbCRCH, mbCRCL; | |
// -------- interfacing | |
unsigned char mbhStatus; | |
unsigned char buffer[50]; | |
unsigned char buffer_length; | |
unsigned char buffer_pointer; | |
inline void buf_reset() { buffer_length = 0; } | |
inline void buf_append(unsigned char value) { buffer[buffer_length] = value; buffer_length++; } | |
void uart_switch_receive() { PORTD &= ~16; bStatus = UART_RECEIVING; } | |
inline void uart_switch_transmit() { PORTD |= 16; bStatus = UART_TRANSMITTING; iTransmissionTimer = iTimer; } | |
unsigned char uart_send() | |
{ | |
if (buffer_pointer == buffer_length) return 0; | |
UDR = buffer[buffer_pointer]; | |
buffer_pointer++; | |
return 1; | |
} | |
SIGNAL (SIG_USART_TRANS) | |
{ | |
if (bStatus == UART_RECEIVING) return; | |
if (uart_send() == 0) uart_switch_receive(); | |
} | |
void analyze(unsigned char data); | |
inline void reanalyze(unsigned char data) | |
{ | |
bScanStatus = SS_ADDRESS; | |
analyze(data); | |
} | |
void uart_process_input() | |
{ | |
if (mbCommand == MC_READ) | |
{ | |
buf_reset(); | |
buf_append(ADDRESS); | |
buf_append(MC_READ); | |
unsigned char bytesize = mbAmountL * 2; | |
buf_append(bytesize & 0xFF); | |
for(unsigned int port=mbRegisterL; port < mbRegisterL+mbAmountL; port++) | |
{ | |
unsigned int value = modbus_read_holding(port); | |
if (mbhStatus == MODBUS_HANDLE_ERR) return; | |
buf_append((unsigned char)(value >> 8)); | |
buf_append((unsigned char)(value & 0xFF)); | |
} | |
} else | |
if (mbCommand == MC_WRITE) | |
{ | |
buf_reset(); | |
buf_append(ADDRESS); | |
buf_append(MC_WRITE); | |
buf_append(0); | |
buf_append(mbRegisterL); | |
unsigned int value = modbus_write_holding(mbRegisterL, mbValueL); | |
if (mbhStatus == MODBUS_HANDLE_ERR) return; | |
buf_append((unsigned char)(value >> 8)); | |
buf_append((unsigned char)(value & 0xFF)); | |
} | |
crc_calculate(); | |
buf_append(mbCRCH); | |
buf_append(mbCRCL); | |
buffer_pointer = 0; | |
uart_switch_transmit(); | |
uart_send(); | |
} | |
void analyze(unsigned char data) | |
{ | |
switch (bScanStatus) | |
{ | |
case (SS_ADDRESS): | |
if (data == ADDRESS) bScanStatus = SS_COMMAND; | |
break; | |
case (SS_COMMAND): | |
if ((data == MC_WRITE) || (data == MC_READ)) | |
{ | |
bScanStatus = SS_REGISTER_H_RW; | |
mbCommand = data; | |
} else reanalyze(data); break; | |
case (SS_REGISTER_H_RW): | |
if (data == 0) | |
bScanStatus = SS_REGISTER_L_RW; | |
else reanalyze(data); break; | |
case (SS_REGISTER_L_RW): | |
if (data <= MAXREGISTER) | |
{ | |
mbRegisterL = data; | |
bScanStatus = ((mbCommand == MC_WRITE) ? SS_VALUE_H_W : SS_AMOUNT_H_R); | |
} | |
else reanalyze(data); break; | |
case (SS_VALUE_H_W): | |
if (data == 0) | |
bScanStatus = SS_VALUE_L_W; | |
else reanalyze(data); break; | |
case (SS_VALUE_L_W): // this step must calculate CRC | |
mbValueL = data; | |
buf_reset(); | |
buf_append(ADDRESS); | |
buf_append(MC_WRITE); | |
buf_append(0); | |
buf_append(mbRegisterL); | |
buf_append(0); | |
buf_append(mbValueL); | |
crc_calculate(); | |
bScanStatus = SS_CRC_H; | |
break; | |
case (SS_AMOUNT_H_R): | |
if (data == 0) | |
bScanStatus = SS_AMOUNT_L_R; | |
else reanalyze(data); break; | |
case (SS_AMOUNT_L_R): // this step must calculate CRC | |
if ((data <= MAXREGISTER + 1 - mbRegisterL) && (data > 0)) | |
{ | |
mbAmountL = data; | |
buf_reset(); | |
buf_append(ADDRESS); | |
buf_append(MC_READ); | |
buf_append(0); | |
buf_append(mbRegisterL); | |
buf_append(0); | |
buf_append(mbAmountL); | |
crc_calculate(); | |
bScanStatus = SS_CRC_H; | |
} | |
else reanalyze(data); break; | |
case (SS_CRC_H): | |
if (data == mbCRCH) | |
bScanStatus = SS_CRC_L; | |
else reanalyze(data); break; | |
case (SS_CRC_L): | |
if (data == mbCRCL) | |
{ | |
uart_process_input(); | |
bScanStatus = SS_ADDRESS; | |
} | |
else reanalyze(data); break; | |
} | |
} | |
SIGNAL (SIG_USART_RECV) | |
{ | |
unsigned char data = UDR; | |
analyze(data); | |
} | |
void uart_init() | |
{ | |
bScanStatus = SS_ADDRESS; | |
UBRRH = 0; | |
UBRRL = 11; | |
UCSRC = (1<<URSEL)|(3<<UCSZ0); | |
UCSRB |= (1<<TXCIE)|(1<<RXCIE)|(1<<RXEN)|(1<<TXEN); | |
uart_switch_receive(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define MODBUS_HANDLE_OK 0 | |
#define MODBUS_HANDLE_ERR 1 | |
#define UART_TRANSMITTING 0 | |
#define UART_RECEIVING 1 | |
unsigned char mbhStatus; | |
unsigned char mbCRCH, mbCRCL; | |
unsigned char buffer_length; | |
unsigned char buffer[50]; | |
unsigned char bStatus; | |
unsigned int iTransmissionTimer; | |
void uart_switch_receive(); | |
void uart_init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment