/**
* @UART
*/
// JP2 pin2 (T2OUT) connected to pin3 of COM-port (through the FTDI)
// thus the configuration for the USART1 (not the USART0)
#include "myUart.h"
unsigned char RS232_ReadChar(void) {
// Wait until a data is available
while (!(UCSR0A & (1 << RXC0)))
{
asm volatile("nop");
}
return UDR0;
}
unsigned char RS485_ReadChar(void) {
while (!(UCSR1A & (1 << RXC1))) {
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
}
return UDR1;
}
// This function writes the given "data" to the USART
// which transmits it via TX line
void RS232_WriteChar(unsigned char data) {
// Wait until the transmitter is ready
while (!(UCSR0A & (1 << UDRE0)))
{
asm volatile("nop");
}
// Now write the data to USART buffer
UDR0 = data;
}
void RS485_WriteChar(unsigned char data) {
while (!(UCSR1A & (1 << UDRE1))) {
asm volatile("nop");
}
UDR1 = data;
}
void displayTelegram(char *message, uint8_t* myTelegram) {
uint8_t i;
// display telegram
RS232_putstring("\r\n");
RS232_putstring(message);
for (i = 0; i < 14; i++) {
print_hexByte(myTelegram[i]);
RS232_putstring(" ");
}
RS232_putstring("\r\n");
}
uint8_t* RS485_QueryTelegram(uint8_t* myTelegram) {
// function is blocking when MM not connected,
// thus a time-out loop must be added
uint8_t i;
// send telegram
for (i = 0; i < 14; i++) {
RS485_WriteChar(myTelegram[i]);
}
// clean the buffer
for (i = 0; i < 14; i++) {
myTelegram[i] = 0xFF;
}
// read telegram
for (i = 0; i < 14; i++) {
// must connect the MM first
myTelegram[i] = RS485_ReadChar();
}
return myTelegram;
}
void RS232_putstring(char* StringPtr) {
while (*StringPtr != 0x00) {
RS232_WriteChar(*StringPtr);
StringPtr++;
}
}
void RS485_putstring(char* StringPtr) {
while (*StringPtr != 0x00) {
RS485_WriteChar(*StringPtr);
StringPtr++;
}
}
//USART0
void RS232_init(uint32_t baudrate) {
uint8_t prescaller = ((F_CPU / (baudrate * 16UL))) - 1;
UBRR0H = (uint8_t) (prescaller >> 8);
UBRR0L = (uint8_t) (prescaller);
UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
}
// USART1: RS485 parity for the MM is always EVEN!!!
void RS485_init(uint32_t baudrate) {
uint8_t prescaller = ((F_CPU / (baudrate * 16UL))) - 1;
UBRR1H = (uint8_t) (prescaller >> 8);
UBRR1L = (uint8_t) (prescaller);
UCSR1B |= (1 << RXEN1) | (1 << TXEN1); // Enable receiver and transmitter
UCSR1C |= (1 << UCSZ10) | (1 << UCSZ11); // Table 80. UCSZn Bits Settings (page 191)
UCSR1C |= (1 << UPM11);
UCSR1C &= ~(1 << UPM10); // even parity enabled
UCSR1C &= ~(1 << USBS0); // Sets 1 stop bits
UCSR1C &= ~(1 << UMSEL1); //asynchronous mode
}
////////////////////////////////////////////////////////////////////////////////
/**
* @USS protocol
*/
#include "usscalc.h"
//ppo1: stx, lge, adr, (word1: pkeHi, pkeLo), (word2: indHi, indLo),
// (word3: pwe1Hi, pwe1Lo), (word4: pwe2Hi, pwe2Lo), pzd1Hi, pzd1Lo, bcc
#define ppo 1
#define mirror 0
#define pkw 0
// AK: bit 15-12 (0-f << 1111 0000 0000 0000) - Auftrag oder Antwort-ID
// 1 Request parameter
// 2 Change parameter value (word) [RAM only]
// 3 Change parameter value (double word) [RAM only]
// 4 Request description element
#define AK 0x00
// SP: bit 11 (0000 1000 0000 0000) - Spontanmeldebearbeitung
#define mySP 0
// PNU: bit 0-10 (0000 0111 1111 1111) - parameter-nummer
#define PNU 0x12bc
// PNEex: bit 15-12
#define PNUex 0x00
// IDX: bit 0-7 (1111 1111) - array index (subindex)
#define IDX 0x00
uint8_t calcBCC() {
uint8_t previous = 0;
uint8_t i = 0;
do {
previous = previous ^ myTelegram[i]; // XOR
i++;
} while (i < 13);
return previous;
}
// ver 2.04
void prepTelegram(uint16_t myPNU) {
// stx, lge, adr,
// pke: pkeHi, pkeLo,
// ind: indHi, indLo,
// pwe1: pwe1Hi, pwe1Lo,
// pwe2: pwe2Hi, pwe2Lo,
// pzd1: pzd1Hi, pzd1Lo,
// bcc
myTelegram[0] = 0x02; // indicates the start of a message
myTelegram[1] = 0x0c; // length
// address: the number of RS485 slave-node
myTelegram[2] = (0x00 | (mirror << 6));
// PKE: parameter number (PNU)
myPNU = myPNU | 0x1000; // set 'response' bit
myTelegram[3] = ((0 | myPNU | (AK << 12) | (mySP << 11)) & 0xff00) >> 8;
// AK
myTelegram[4] = (0 | myPNU | (AK << 12) | (mySP << 11)) & 0x00ff;
// IND: for MicroMaster non-significant
myTelegram[5] = ((PNUex << 12) & 0xff00) >> 8;
myTelegram[6] = IDX & 0x00ff; // command
// PWE1: 1st parameter value, high-order word
myTelegram[7] = 0x00;
myTelegram[8] = 0x00;
// PWE2: 2nd parameter value, low-order word
myTelegram[9] = 0x00;
myTelegram[10] = 0x00;
// PZD1: control status word
myTelegram[11] = 0x00;
myTelegram[12] = 0x00;
// control sum
myTelegram[13] = calcBCC();
}
uint16_t getValue(uint16_t myParam) {
uint8_t *mmResponsePtr;
uint16_t myShort;
prepTelegram(myParam);
// send query and get response (14 bytes)
mmResponsePtr = RS485_QueryTelegram(myTelegram);
// bytes [7] and [8] are the response value
myShort = (mmResponsePtr[7] << 8) | mmResponsePtr[8];
return myShort;
}
uint16_t * getAllValues(uint16_t* mmParametersArr, uint8_t length) {
uint8_t i;
static uint16_t myValueArray[127];
for (i = 0; i < length; i++) {
myValueArray[i] = getValue(mmParametersArr[i]);
}
heartbeat++; // still alive
return myValueArray;
}