Здравствуйте, прошу помощи... Не могу запустить код modbus на Atmega328. Этот код хорошо работает на atbanned62, atmega8. Но на 328 даже если не отправлять запрос на устройство о чтении регистров, контроллер постоянно шлёт какой-то бред.
Код прилагаю, взят с вашего форума. Может различия в таймере?
Код:
'modbus.lib contains the crcMB function
$lib "modbus.lbx"
$regfile = "m328def.dat" ' chip used
$crystal = 14745600 ' xtal used
$baud = 19200 ' baudrate N,8,1
Dim Mbuf(255) As Byte , Modc As Byte , Modt As Byte , Modw As Word
Dim Table_data(30) As Word 'таблица с данными (текущие значения измерений, слова входов выходов уставки, настройки )
Dim Tmp As Word 'промежуточные переменные
Dim Tmp_byte As Byte 'промежуточные переменные
Dim Tmp_byte2 As Byte
Dim Tmp_byte_modbus As Byte
Dim N_word As Byte 'количество слов в посылке
Dim N_byte As Byte 'количество байт в посылке
Dim Beg_adr As Byte 'начальный адрес данных
Dim Beg_adr_w As Byte ' адрес данных при записи
Dim I As Byte 'счетчик циклов в for
Dim Cnt_print As Byte
Dim Error_mod As Integer ' код ошибки
Dim Frame_value As Byte 'значение паузы между фреймами загружаемое в счетчик
' параметры для записи в энергонезависимую память
Dim W_to_device As Byte 'признак записи в устройство
Dim Modbus_slave As Eram Byte 'адрес устройства в сети Modbus
Dim Frame_value_dev As Eram Byte 'значение паузы между фреймами
Dim Ust1_up As Eram Integer 'уставка1 верхняя
Dim Ust1_dwn As Eram Integer 'уставка1 нижняя
Dim Md_t_start As Bit
Config Timer0 = Timer , Prescale = 256 'организация задержки отключения разрешения передачи, при передаче на порт 485 '4000000 0,065536 сек (15,25878906 в 1 секунду) 8000000 0,032768 30,51757813
On Timer0 Modbus_timers
' **************** выходы*************
'Config Portd.4 = Output
Config Portc.4 = Output
'Test_light Alias Portc.0
Enable_tx Alias Portc.4 'разрешение на передачу по 485
' **************** 0
Declare Sub Send_to_master 'подпрограмма передачи ответа мастеру
Declare Sub Error_modbus 'подпрограмма формирования ошибки модбас
' Config Portc = Output 'настроим порт с как выходы
Modc = 0 'инициализация
W_to_device = 0
Error_mod = 0
Cnt_print = 0
Frame_value = Frame_value_dev
If Frame_value = 255 Then Frame_value = 253
'ВАЖНО! - После Перопрошивки Значение Modbus_slave = 255 !!!!!!!
Tmp_byte = Modbus_slave ' нельзя писать ерам байт в инт. можно через промежуточную переменную
Table_data(11) = Tmp_byte ' адрес 4010 - номер устройства в сети модбас (читать писать)
Table_data(12) = Ust1_up ' адрес 4011 - уставка верх (читать писать)
Table_data(13) = Ust1_dwn ' адрес 4012 - уставка низ (читать писать)
Table_data(16) = Frame_value ' адрес 4015 - значение TIMER0 загружаемое при старте таймера TIMER0 (читать)
On Urxc Urxc_isr 'прерывание по приему UART
Enable Urxc
On Utxc Utxc_isr 'прерывание по передаче UART
Enable Timer0
Enable Interrupts
For I = 0 To 9 'заполняем для примера
Tmp_byte = I + 1
Table_data(tmp_byte) = I
Next
Do 'начало основного цикла
'Важно!!! не использовать wait !!!
If Md_t_start = 1 Then ' если время между принятыми байтами больше 3.5 символа, в буфере принят фрейм
Md_t_start = 0 ' обнуляем все признаки
Error_mod = 0 ' обнуляем ошибку и начинаем разбирать принятый фрейм из буфера.
If Mbuf(1) = Modbus_slave Or Mbuf(1) = 0 Then 'первый байт это адрес устройства
Tmp_byte = Modc - 1 ' вычисляем адреса для расчета CRC
Tmp_byte2 = Modc ' вычисляем адреса для расчета CRC
Modw = Makeint(mbuf(tmp_byte) , Mbuf(tmp_byte2)) ' считываем из принятого фрейма CRC
Tmp_byte = Modc - 2 ' вычисляем адреса для расчета CRC
Tmp = Crcmb(mbuf(1) , Tmp_byte) ' вычисляем CRC из фрейма принятых данных
If Modw = Tmp Then ' сравниваем расчитанный CRC и принятый CRC
'справедливо для функций 3,4 и 5,6.Если будут другие функции кроме 3,4 или 5,6 то добавить сравнение с функциями
Beg_adr = Makeint(mbuf(4) , Mbuf(3))
Incr Beg_adr 'адрес региста чтения (увеличиваем на 1 так как индекс массива начинается от 1, а адресация идет с 0 - 4000 адрес)
'второй байт это номер функции
Select Case Mbuf(2)
Case 3: 'функция 3- чтение регистров
N_word = Makeint(mbuf(6) , Mbuf(5)) 'количество слов чтения
If N_word > 27 Then 'я ограничил количество 27 словами
N_word = 1 ' формируем ошибку если в запросе на чтение больше 27 слов
Error_mod = 2 'если превышение размера буфера то формируем ошибку 2 - неправильный адрес
End If
N_byte = N_word + N_word 'количество слов переводим в кол. байт
Mbuf(3) = N_byte 'кол считываемых байт byte count wieviele Bytes sollen gesendet werden
Tmp_byte = 4 'начинаем считать с 4-го байта(1-ый байт данных)
'************************ здесь был косяк For I = Beg_adr To N_word
Tmp_byte2 = Beg_adr + N_word 'формируем индекс количества слов с учетом смещения от начального адресаа
For I = Beg_adr To Tmp_byte2 'цикл записи в буфер обмена запрашиваемого количества слов
Tmp_byte_modbus = High(table_data(i)) 'разбираем по байтам на старший байт
Mbuf(tmp_byte) = Tmp_byte_modbus ' запись в буфер обмена с разбивкой на байты (таблица данных)
Incr Tmp_byte '
Tmp_byte_modbus = Low(table_data(i)) 'разбираем по байтам на младший байт
Mbuf(tmp_byte) = Tmp_byte_modbus 'запись в буфер обмена с разбивкой на байты (таблица данных)
Incr Tmp_byte '
Next I
N_byte = N_byte + 3 'номер последнего байта передаваемых в посылке слов с данными (таблица данных) 3-количество байт перед данными (номер устройства, функция, количество передаваемых слов )
Modw = Crcmb(mbuf(1) , N_byte) ' create checksum
Incr N_byte 'номер предпоследнего байта во всей посылке () (CRC LOW)
Mbuf(n_byte) = Low(modw) 'Checksumme LOWer Byte
Incr N_byte 'номер последнего байта во всей посылке (CRC High)
Mbuf(n_byte) = High(modw) 'Checksumme HIGHer Byte
Case 6: 'функция 6- запись одного регистра
Table_data(beg_adr) = Makeint(mbuf(6) , Mbuf(5)) 'записываем полученное значение
W_to_device = 1 'формируем признак записи в устройство
Beg_adr_w = Beg_adr 'номер слова для записи в память
N_byte = 8 'длина посылки для функции 6 всегда =8 байт
Case Else:
Error_mod = 1 'неподдерживаемая функция
End Select
If Error_mod > 0 Then
Call Error_modbus 'код ошибки неправильный функциональный код
End If
Call Send_to_master 'ответ мастеру
Else 'если неправильная контрольная сумма
Error_mod = 3 'код ошибки Checksumme
Call Error_modbus
Call Send_to_master 'ответ мастеру
End If
End If
Modc = 0
End If
If W_to_device = 1 Then 'при наличии признака записи в устройство (уставки, настройки, выходыи т.д.)
Select Case Beg_adr_w 'при записи (функция 6) Beg_adr = индексу в массиве Table_data
Case 1 : 'Portc = Low(table_data(beg_adr)) 'запись в выходной порт состояния 0 регистра
Case 11 : ' адрес 4010 - номер устройства в сети модбас (читать писать)
Modbus_slave = Table_data(beg_adr_w) 'запись в энергонезависимую память
Case 12 : ' адрес 4011 - уставка верх (читать писать)
Ust1_up = Table_data(beg_adr_w) 'запись в энергонезависимую память
Case 13 : ' адрес 4012 - уставка низ (читать писать)
Ust1_dwn = Table_data(beg_adr_w) 'запись в энергонезависимую память
Case 14: ' Frame_value=делитель -(время в мс / заданное значение времени прерывания за один такт) 256-(время в мс/0.0032)
Tmp = Table_data(beg_adr_w) * 100
Tmp = Tmp \ 32
Table_data(15) = Tmp
Frame_value = 256 - Tmp
Table_data(16) = Frame_value 'от 1 до 82мсек
Frame_value = Frame_value_dev
End Select
W_to_device = 0
End If
Loop
Urxc_isr: ' прерывание по приему данных
sbis usr,7 ' Wait for character
rjmp urxc_isr ' wait until we can read the byte
Modt = Udr ' get the byte
Load Timer0 Frame_value 'устанавливаем значение таймера тишины между фреймами
Start Timer0 'стартуем таймер фрейма
Incr Modc 'увеличиваем счетчик принятого байта
Mbuf(modc) = Modt ' пишем в буфер значение принятого байта
Return
Utxc_isr:
'Подпрограмма передачи данных
If Cnt_print = 1 Then ' если последний байт передан
Enable_tx = 0 ' разрешаем прием (запрещаем передачу )
Cnt_print = 0 ' обнуляем признак последнего байта передачи
Disable Utxc ' запреаем прерывание.
End If
Return
Sub Send_to_master
Enable Utxc 'разрешаем прерывание по
If Enable_tx = 0 Then
Enable_tx = 1
For I = 1 To N_byte 'ответ мастеру. цикл для передачи буфера обмена с заданным кол. байт c заданного адреса
Print Chr(mbuf(i)); 'отправка буфера обмена в Нех
Next
Cnt_print = 1
End If
End Sub
Sub Error_modbus 'функция формирования пакета исключительного ответа мастеру по ошибке.
Mbuf(2).7 = 1 ' 1дрес,2функц.код с 1(единицей),3код ошибки,4,5CRC всего 5 байт
Mbuf(3) = Error_mod 'код ошибки (1- неправильный фунциональный код(неподдерживаемая функция); 2- неправильный адрес; 3- неправильные данные (CRC). )
Modw = Crcmb(mbuf(1) , 3) ' create checksum
Mbuf(4) = Low(modw) 'Checksumme LOWer Byte
Mbuf(5) = High(modw) 'Checksumme HIGHer Byte
N_byte = 5
End Sub
Modbus_timers: 'прерывание по таймеру. В нем организовано два счетчика. По одному счетчику обработка пакета принятых сообщений модбас, по другому задержка на отключение передатчика TX в 485.
Stop Timer0 'останавливаем прерывание по таймеру тишины между фреймами
Md_t_start = 1 'выставляем признак того, что в буфере принят фрейм
Return