Отправка последовательности переменной длины по последовательному каналу с ПК на Mega
Я пытаюсь отправить последовательность команд с ПК на Мега. Mega, в свою очередь, управляет 2 генераторами сигналов (AD9833).
Последовательности могут отличаться по длине, но всегда имеют один и тот же формат:
- Начальный байт 255
- Длина последовательности
- Элементы последовательности: Канал 0: MSB, LSB и форма волны, Канал 1: MSB, LSB и форма волны
Код на стороне ПК:
import serial
import struct
usbport = 'COM3'
ser = serial.Serial(usbport, 9600, timeout=1)
def sendSequence(seq):
''' Send a sequence of frequencies along with waveform '''
# Start byte & sequence length
ser.write(struct.pack('>B', 255))
ser.write(struct.pack('>B', len(seq)))
for s in seq:
print(s)
MSB, LSB = (s[0] & 0xFFFF).to_bytes(2, 'big') # Split frequency to send
ser.write(struct.pack('>B', MSB))
ser.write(struct.pack('>B', LSB))
ser.write(struct.pack('>B', s[1])) # Waveform
combined = ((MSB & 0xFF) << 8) | (LSB & 0xFF)
print(combined)
sendSequence([[1000, 0], [1000, 0], [2000, 0], [1000, 0], [2000, 0], [2000, 0]])
ser.close()
На стороне Arduino:
#include <SPI.h>
// Set up Serial data variables
byte freq_MSB;
byte freq_LSB;
int startbyte;
unsigned long freq_seq_ch_0[16];
int wave_seq_ch_0[16];
unsigned long freq_seq_ch_1[16];
int wave_seq_ch_1[16];
int wave_select = 0;
int seq_length;
long f_2;
long f_1;
const int SINE = 0x2000; // Define AD9833's waveform register value.
const int SQUARE = 0x2028; // When we update the frequency, we need to
const int TRIANGLE = 0x2002; // define the waveform when we end writing.
int wave = SINE;
const float refFreq = 25000000.0; // On-board crystal reference frequency
const int FSYNCA = 53; // Standard SPI pins for the AD9833 waveform generator.
const int FSYNCB = 49;
const int CLK = 52;
unsigned long pause = 5000;
unsigned long freq = 1000; // Set initial frequency.
int i;
void setup() {
// Set slave ocntrol pins
pinMode(FSYNCA, OUTPUT);
pinMode(FSYNCB, OUTPUT);
digitalWrite(FSYNCA, HIGH);
digitalWrite(FSYNCB, HIGH);
// Set up SPI
SPI.begin();
SPI.setDataMode(SPI_MODE2);
delay(50);
// Set up AD9833s
AD9833reset(); // Reset AD9833 module after power-up.
delay(50);
AD9833setFrequency(freq, SINE, FSYNCA); // Set the frequency and Sine Wave output
AD9833setFrequency(freq, SINE, FSYNCB);
// Open the serial connection, 9600 baud
Serial.begin(9600);
}
void loop() {
// Wait for serial input
if (Serial.available()) {
startbyte = Serial.read(); // Read the first byte
if (startbyte == 255) {
seq_length = Serial.read();
for (i = 0; i < seq_length; i++) {
// Channel 0
freq_MSB = Serial.read();
freq_LSB = Serial.read();
f_2 = (long)freq_MSB << 8;
f_1 = (long)freq_LSB;
freq_seq_ch_0[i] = f_2 | f_1;
wave_select = Serial.read();
switch (wave_select) {
case 0:
wave_seq_ch_0[i] = SINE;
break;
case 1:
wave_seq_ch_0[i] = TRIANGLE;
break;
case 2:
wave_seq_ch_0[i] = SQUARE;
break;
}
// Channel 1
freq_MSB = Serial.read();
freq_LSB = Serial.read();
f_2 = (long)freq_MSB << 8;
f_1 = (long)freq_LSB;
freq_seq_ch_1[i] = f_2 | f_1;
wave_select = Serial.read();
switch (wave_select) {
case 0:
wave_seq_ch_1[i] = SINE;
break;
case 1:
wave_seq_ch_1[i] = TRIANGLE;
break;
case 2:
wave_seq_ch_1[i] = SQUARE;
break;
}
}
// Send sequence to signal generators
for (i = 0; i < seq_length; i++) {
AD9833setFrequency(freq_seq_ch_0[i], wave_seq_ch_0[i], FSYNCA);
AD9833setFrequency(freq_seq_ch_1[i], wave_seq_ch_1[i], FSYNCB);
delay(3000);
}
}
}
}
// AD9833 documentation advises a 'Reset' on first applying power.
void AD9833reset() {
WriteRegister(0x100, FSYNCA); // Write '1' to AD9833 Control register bit D8.
delay(10);
WriteRegister(0x100, FSYNCB);
delay(10);
}
// Set the frequency and waveform registers in the AD9833.
void AD9833setFrequency(long frequency, int Waveform, int channel) {
long FreqWord = (frequency * pow(2, 28)) / refFreq;
int MSB = (int)((FreqWord & 0xFFFC000) >> 14); //Only lower 14 bits are used for data
int LSB = (int)(FreqWord & 0x3FFF);
//Set control bits 15 ande 14 to 0 and 1, respectively, for frequency register 0
LSB |= 0x4000;
MSB |= 0x4000;
WriteRegister(0x2100, channel);
WriteRegister(LSB, channel); // Write lower 16 bits to AD9833 registers
WriteRegister(MSB, channel); // Write upper 16 bits to AD9833 registers.
WriteRegister(0xC000, channel); // Phase register
WriteRegister(Waveform, channel); // Exit & Reset to SINE, SQUARE or TRIANGLE
}
void WriteRegister(int dat, int channel) {
// Display and AD9833 use different SPI MODES so it has to be set for the AD9833 here.
//SPI.setDataMode(SPI_MODE2);
digitalWrite(channel, LOW); // Set FSYNC low before writing to AD9833 registers
delayMicroseconds(10); // Give AD9833 time to get ready to receive data.
SPI.transfer(highByte(dat)); // Each AD9833 register is 32 bits wide and each 16
SPI.transfer(lowByte(dat)); // bits has to be transferred as 2 x 8-bit bytes.
digitalWrite(channel, HIGH); //Write done. Set FSYNC high
}
Моя проблема в том, что это НИЧЕГО НЕ дает. Независимо от того, какую последовательность я отправляю, выходные данные генераторов сигналов никогда не отклоняются от заданных значений по умолчанию.
Генераторы действительно работают, и мне раньше удавалось управлять ими через последовательный, но в этом случае я точно знал, сколько информации будет в последовательном буфере, прежде чем я ее прочитаю, но в этом случае длина последовательности априори неизвестна.
Это серийная проблема?
@DrBwts, 👍-1
Обсуждение1 ответ
Основная проблема здесь в том, что вы читаете данные, которые, возможно, еще не получены. Это:
if (Serial.available()) {
проверит, есть ли какие-либо данные в последовательном буфере. Поскольку код выполняется довольно быстро, а связь по последовательному каналу со скоростью 9600 бод относительно медленная, это вполне может быть правдой, если ваше сообщение было получено не полностью. Таким образом, вы, возможно, получили начальный байт, но остальные данные все еще передаются. В этом случае Serial.read()
вернет -1
.
С последовательным (UART) передача происходит с отдельными байтами, а не большими порциями. Вам нужно только прочитать данные, которые действительно получены.
Поскольку вы заранее не знаете длину последовательности, я бы предложил 2 разных способа:
Вы можете подождать, пока в последовательном буфере будет 2 байта (начальный байт и длина), а затем снова подождать, пока в последовательном буфере не будет достаточно дополнительных байтов (поскольку теперь у вас есть длина последовательности).
Вы можете перестроить свой код так, чтобы он просто помещал данные в дополнительный буфер, пока вы не получите достаточно данных (которые вам нужно проверить с помощью полученного байта длины). Затем, когда вы получили полное сообщение, вы обрабатываете его, а затем очищаете буфер, ожидая нового сообщения.
Итак, я добавил " if (Serial.available > 1)", а затем добавил " while (Serial.available < seq_length*3){}` но он все еще ничего не делает., @DrBwts
- Как разделить входящую строку?
- Какова максимальная длина провода для последовательной связи между двумя Arduino?
- Последовательная связь между двумя Arduino (запрос и получение)
- Не нашел датчик отпечатков пальцев :( Arduino Mega 2560 Adafruit Fingerprint Sensor
- Модуль SIM808: команда определения местоположения GSM (AT+CIPGSMLOC=1,1) дает неверное значение после выполнения команды отправки сообщения (AT+CMGS=+91xxxxxxxx)
- Как правильно получить MIDI с Arduino, с 6n138?
- Bluetooth-модуль HC-05 не принимает AT-команды
- Сбой Arduino во время последовательной печати без очевидной причины
Вы ждете после открытия последовательного порта в Python, чтобы Arduino перезагрузился и запустил загрузчик перед отправкой данных?, @Majenko
@Majenko Я добавил `sleep(1.0) " в код Python после открытия последовательной связи, но я все равно ничего не получаю, @DrBwts
ОК увеличил это до 10 секунд и эй, престо! это сработало!, @DrBwts