I open this new topic for investigation and developing something not present on internet.
I need Arduino Mega 2560 to communicate via serial (hardware or software) to MDB protocol of NV9 spectral bill validator. The problem is hardware adapter and software to communicate with this validator.
Any help for this project will be appreciated.
Your explanation of the issue is too vague.
You will get faster and better help if you describe your problem in detail and post your code (if any) as requested by the forum guidelines.
Read the forum guidelines to see how to properly ask a question and some good information on making a good post.
I'm at the beginning of the project and over internet information is not very clear, so at this moment I don't have too much information.
I found a thread but it is old and closed with not too much information too.
So, I need to use Arduino Mega to communicate via serial port through adapter to MDB protocol connected to bank note validator NV9 Spectral.
The problem is hardware adapt from TTL to MDB, TTL use 3.3V serial communication 8 bits and MDB use 15V serial communication 9 bits.
Because this project is nowhere over internet available, we can start from investigating to have this communication available. Arduino should be as master (VMC) to communicate with bill validator as slave.
It is definitely possible. The topic of working on Arduino with an MDB interface is very common.
The searching "Arduino + MDB" in the google will give you many useful results.
See this library - it seems that the author solved the connection issue.
You Mega uses 5V, not 3.3V
As I already said looking all over internet for a good solution, I also already know about what you suggested but nothing is available to put in practice. Now, with your help I?'ll put this in practice and finally to have a good communication with NV9 Spectral.
The suggested link has a hardware difficulty problem, not optimized using another atmega. So it is needed to understand signals to have a hardware adapt then software link communication.
Lets say, my arduino Mega will use two serials, one for connection to my PC to check and monitor the communication and the other one to communicate via MDB with NV9.
That's better for my project, sorry for my mistake.
So, do you have any arduino code suggestion to be applied in practice for this project?
What do you mean on "applied in practice" ?
You hardly have to expect to obtain a ready to use code for your project. It is your task to get an available examples, like cited in #4, and applied it to work with your hardware.
I mean already tested and working code. The example suggested in #4 does not have arduino file code and more than this the hardware is much more complex. I need a software code which help me to communicate via serial from TTL 8bits to MDB 9bits. I have with this code to communicate with validator, send and receive messages but I can't find anywhere this type of communication.
This is not Arduino code, but it is also C. And as far as I understand from the description, this is exactly the code for the bridge between the standard 8bit UART and the 9bit MDB bus.
If you have visited the github site and read the documentation, it mentions another MDB project that it was based on and that project is totally Arduino code.
Yes it is C code and it's not suitable for this project. How could I add changes later without compilation? We can't consider that project part of arduino development.
This project is another one working with two arduino not a real validator, it is totally different and does not fit with my project.
There may be parts of the code that are extremely useful, like implementing the basic components of the communications protocol. A lot of work went into the code on the Github sites, so take the time to understand what it does.
As others have said, you are going to have to put a lot of work into this project, and so far, all you seem to have done is discount very useful sources of information and code fragments.
Aren't you know that Arduino is a C/C++ code too? The C source code can be easily added to Arduino project and compiled with Arduino compiler.
You have right, the code is very interesting to be analyzed and adapted and the project is not so easy. This is why I came to you to give me maybe a suggestion already tested by someone. There are so many thing to take into consideration like hardware and software protocol adapt and these should be taken step by step to progress.
For example, how could I check first the hardware adapt is good, what signal to measure to have first response from bill validator?
Does it work C code in arduino compiler? Isn't it just C++?
The C and C++ are closely related. C sources can used in C++ project. The Arduino itself is a C++ project, but C sources are widely used in Arduino packages and libraries.
in my google search I found this link below which has the code attached more appropriate but for me does not work.
#include <avr/wdt.h>
#define BAUD 9600
#define ADDRESS_MASK (0xF8) // Первый байт сообщения состоит из адреса устройства (биты 7,6,5,4,3)
#define COMMAND_MASK (0x07) // и кода команды (биты 2,1,0)
// Адреса всех устройств (MDB Version 4.2, page 25)
#define ADDRESS_VMC (0x00) // Reserved!!!
#define ADDRESS_CHANGER (0x08) // Coin Changer
#define ADDRESS_CD1 (0x10) // Cashless Device 1
#define ADDRESS_GATEWAY (0x18) // Communication Gateway
#define ADDRESS_DISPLAY (0x20) // Display
#define ADDRESS_EMS (0x28) // Energy Management System
#define ADDRESS_VALIDATOR (0x30) // Bill Validator
#define ADDRESS_USD1 (0x40) // Universal satellite device 1
#define ADDRESS_USD2 (0x48) // Universal satellite device 2
#define ADDRESS_USD3 (0x50) // Universal satellite device 3
#define ADDRESS_COIN1 (0x58) // Coin Hopper 1
#define ADDRESS_CD2 (0x60) // Cashless Device 2
#define ADDRESS_AVD (0x68) // Age Verification Device
#define ADDRESS_COIN2 (0x70) // Coin Hopper 2
//это автоматическая настройка скорости
#include <util/setbaud.h>
// MDB 9-bit определяется как два байта
struct MDB_Byte {
byte data;
byte mode;
};
//массив команд *POLL* для каждого из устройств (включая адрес)
byte POLL_ADDRESS[10]{0x0B, 0x12, 0x1A, 0x33, 0x42, 0x4A, 0x52, 0x5B, 0x62, 0x73};
byte EXT_UART_BUFFER[37]; //входящий буфер для полученной команды от VMC
struct MDB_Byte MDB_BUFFER[37]; //входящий буфер для полученной команды от MDB устройства
int EXT_UART_BUFFER_COUNT;
volatile int MDB_BUFFER_COUNT;
//флаги состояния получениях данных от MDB
int rcvcomplete; //сообщение MDB получено
int mdboverflow; //сообщение MDB ошибочно
void MDB_Setup() {
// установка скорости порта через setbaud.h
UBRR2H = UBRRH_VALUE;
UBRR2L = UBRRL_VALUE;
// Выключение USART rate doubler (arduino bootloader остается включен...)
UCSR2A &= ~(1 << U2X2);
// установка 9600-9-N-1 UART режима
UCSR2C = (0<<UMSEL21)|(0<<UMSEL20)|(0<<UPM21)|(0<<UPM20)|(0<<USBS2)|(1<<UCSZ21)|(1<<UCSZ20);
UCSR2B |= (1<<UCSZ22); // 9bit
// включаем rx/tx
UCSR2B |= (1<<RXEN2)|(1<<TXEN2);
}
void EXT_UART_Setup()
{
Serial1.begin(9600);
}
void EXT_UART_read() {//получаем команду от VMC
EXT_UART_BUFFER_COUNT = 0; //ставим размер буфера 0
while (Serial1.available()) {
//записываем все данные с порта в приемный буфер
EXT_UART_BUFFER[EXT_UART_BUFFER_COUNT++]=Serial1.read(); //и за одно получаем размер этой команды
delay(20); //задержка а то команда не успевает приняться целиком
}
if ((EXT_UART_BUFFER_COUNT > 0) && EXT_ChecksumValidate()) {//проверяем: если буфер больше 0 и контрольная сумма верна
//Serial1.print("Recvd CMD: "); //отправляем на хост подтвержденеи принятой команды
//for (int a = 0; a < EXT_UART_BUFFER_COUNT; a++){
// if (EXT_UART_BUFFER[a] < 16) Serial1.print("0");
// Serial1.print(EXT_UART_BUFFER[a], HEX);
// }
//Serial1.println();
bool IsAddressValid = false;
switch(EXT_UART_BUFFER[0] & ADDRESS_MASK) { //проверяем правильность первого байта, на соответствие из таблицы
case ADDRESS_CHANGER : IsAddressValid = true; break;
case ADDRESS_GATEWAY : IsAddressValid = true; break;
case ADDRESS_DISPLAY : IsAddressValid = true; break;
case ADDRESS_EMS : IsAddressValid = true; break;
case ADDRESS_VALIDATOR: IsAddressValid = true; break;
case ADDRESS_AVD : IsAddressValid = true; break;
case ADDRESS_CD1 : IsAddressValid = true; break;
case ADDRESS_CD2 : IsAddressValid = true; break;
case ADDRESS_USD1 : IsAddressValid = true; break;
case ADDRESS_USD2 : IsAddressValid = true; break;
case ADDRESS_USD3 : IsAddressValid = true; break;
case ADDRESS_COIN1 : IsAddressValid = true; break;
case ADDRESS_COIN2 : IsAddressValid = true; break;
default:
break;
}
if (IsAddressValid){ //если команда правильная, то пробуем отправить ее на MDB
struct MDB_Byte AddressByte;
int addrtx = 0;
AddressByte.data = EXT_UART_BUFFER[0];
AddressByte.mode = 0x01;
memcpy(&addrtx, &AddressByte, 2);
MDB_write(addrtx); //пишем адрес на MDB
for (int i = 1; i < EXT_UART_BUFFER_COUNT; i++){ //пишем остальные байты команды из EXT, включая CRC
MDB_write(EXT_UART_BUFFER[i]);
}
processresponse(EXT_UART_BUFFER[0] & ADDRESS_MASK);
}
}
}
void MDB_checksumGenerate() {
byte sum = 0;
for (int i=0; i < (EXT_UART_BUFFER_COUNT); i++)
sum += EXT_UART_BUFFER[i];
EXT_UART_BUFFER[EXT_UART_BUFFER_COUNT++] = (sum & 0xFF);//only first 8 bits are checksum
}
void MDB_write(int data) {
struct MDB_Byte b;
memcpy(&b, &data, 2);
write_9bit(b);
}
void write_9bit(struct MDB_Byte mdbb) {
while ( !( UCSR2A & (1<<UDRE2)));
if (mdbb.mode) {
//turn on bit 9
UCSR2B |= (1<<TXB82);
} else {
//turn off bit 9
UCSR2B &= ~(1<<TXB82);
}
UDR2 = mdbb.data;
}
int MDB_Receive() {
unsigned char resh, resl;
char tmpstr[64];
int rtr = 0;
// Wait for data to be received
while ((!(UCSR2A & (1<<RXC2))) and rtr < 50) {
delay(1);
rtr++;
}
if (rtr == 50){
mdboverflow = 1;
rcvcomplete = 1;
}
// Get 9th bit, then data from buffer
resh = UCSR2B;
resl = UDR2;
// Filter the 9th bit, then return only data w\o mode bit
resh = (resh >> 1) & 0x01;
return ((resh << 8) | resl);
}
void MDB_getByte(struct MDB_Byte* mdbb) {
int b;
b = 0;
b = MDB_Receive();
memcpy (mdbb, &b, 2);
}
byte EXT_ChecksumValidate() {
byte sum = 0;
for (int i=0; i < (EXT_UART_BUFFER_COUNT-1); i++)
sum += EXT_UART_BUFFER[i];
if (EXT_UART_BUFFER[EXT_UART_BUFFER_COUNT-1] == (sum & 0xFF))
return 1;
else
return 0;
}
byte MDB_ChecksumValidate() {
int sum = 0;
for (int i=0; i < (MDB_BUFFER_COUNT-1); i++)
sum += MDB_BUFFER[i].data;
if (MDB_BUFFER[MDB_BUFFER_COUNT-1].data == (sum & 0xFF))
return 1;
else
return 0;
}
void MDB_read() {
MDB_getByte(&MDB_BUFFER[MDB_BUFFER_COUNT]);
MDB_BUFFER_COUNT++;
if (MDB_BUFFER_COUNT == 35){
rcvcomplete = 1;
mdboverflow = 1;
}
if (MDB_BUFFER[MDB_BUFFER_COUNT - 1].mode && MDB_ChecksumValidate()){
rcvcomplete = 1;
}
}
void MDBFlush(){
MDB_BUFFER_COUNT = 0;
Serial.flush();
}
void processresponse(int addr){
mdboverflow = 0;
rcvcomplete = 0;
while (!rcvcomplete){
MDB_read();
}
if ((rcvcomplete) && (!mdboverflow))
{
if (MDB_BUFFER_COUNT > 1){
MDB_write(0x00);// send ACK to MDB if peripheral answer is not just *ACK*, otherwise peripheral will try to send unconfirmed data with next polls
} else{
if (MDB_BUFFER_COUNT == 1){
//just *ACK* received from peripheral device, no confirmation needed
}
}
//finally, send data from peripheral to VMC via serial port as string representation of hex bytes
char buff[5];
//sprintf(buff, "%02x", addr);
Serial1.write(addr);
for (int a = 0; a < MDB_BUFFER_COUNT - 1; a++){
//sprintf(buff, "%02x", MDB_BUFFER[a].data);
Serial1.write(MDB_BUFFER[a].data);
}
//last byte representation will be sent without following space but with EOL to easy handle
//sprintf(buff, "%02x", MDB_BUFFER[MDB_BUFFER_COUNT - 1].data);
Serial1.write(MDB_BUFFER[MDB_BUFFER_COUNT - 1].data);
Serial1.write('\n');
wdt_reset(); //сброс ватчдога. Если связи нет, контроллер будет перезагружен
}
}
void PollDevice(byte devaddrbyte){
struct MDB_Byte addrbyte;
rcvcomplete = 0;
int addrtx = 0;
addrbyte.data = devaddrbyte;
addrbyte.mode = 0x01;
memcpy(&addrtx, &addrbyte, 2);
MDB_write(addrtx);
MDB_write(addrbyte.data);
processresponse(addrbyte.data & ADDRESS_MASK);
}
void setup() {
// put your setup code here, to run once:
wdt_reset(); // reset watchdog counter
wdt_disable();
// delay(10000);
wdt_enable(WDTO_4S); // watchdog 8s timeout
pinMode(0, OUTPUT);
MDB_Setup();
EXT_UART_Setup();
MDB_BUFFER_COUNT = 0;
}
void loop() {
// put your main code here, to run repeatedly:
EXT_UART_read();
MDBFlush();
/* for (int q = 0; q < 10; q++){
PollDevice(POLL_ADDRESS[q]);
MDBFlush();
delay(20);
}*/
}