Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » atmega8 и usart глюки в железе но работает в протейсе, гдето напортач


atmega8 и usart глюки в железе но работает в протейсе, гдето напортач

Сообщений 1 страница 5 из 5

1

Доброго времени суток господа,
собрал небольшое устройство  на  атмеге8 :
измерение
3 канала  АЦП
5 дискретных входов
сохранение состояния дискретных входов в небольшой журнал  в EEPROM
и передача данных  и журнала по rs485  по modbusRTU   на ПК

исходник
Код:
'modbus.lib contains the crcMB function
$lib "modbus.lbx"
$regfile = "m8def.dat"
'$regfile = "m8adef.dat"


Const _crystal = 8000000                                    ' chip used
$crystal = _crystal
' xtal used
'Const Baudrate = 9600
'Const Baudrate = 19200
'Const Baudrate = 38400
'Const Baudrate = 57600
'Const Baudrate = 115200
$baud = 9600
$hwstack = 80
$swstack = 96
$framesize = 80
'===============================================================================
'             И С П О Л Ь З У Е М Ы Е     П Е Р Е М Е Н Н Ы Е
'===============================================================================


Config Com1 = Dummy, Synchrone = 0, Parity = None, Stopbits = 2, Databits = 8, Clockpol = 0
Config Serialin = Buffered, Size = 8, Bytematch = All


Config Scl = Portc.5                                        ' I2c Scl
Config Sda = Portc.4                                        ' I2c Sda
'Config I2cdelay = 1                                       ' Скорость работы шины I2c на программном уровне
I2cinit

Dim Год As Byte
Dim Часы As Byte
Dim Месяц As Byte
Dim Минуты As Byte
Dim Секунды As Byte
Dim День_недели As Byte
Dim Число_месяца As Byte
Dim Флаг_опросить_ds1307 As Byte


Dim Mbuf(65) As Byte, Modc As Byte, Modt As Byte, Modw As Word
Dim Table_data(30) As Word                                  'таблица с данными (текущие значения измерений, слова входов выходов уставки, настройки )
Dim Tmp_table_data(14) As Word                              'таблица с данными (текущие значения измерений, слова входов выходов уставки, настройки )
Dim Tmp As Word
Dim Tmpl_input As Byte
Dim Inputs 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 Serial_numb_l As Eram Byte
Dim Serial_numb_h As Eram 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 Usart_speed As Eram Byte
Const Maximum_input_registers = 30                          ' максимальное количество регистров которое можно прочесть 0-30
Dim Load_timer As Word
Dim Md_t_start As Bit
Dim Tmp_byte As Byte                                        'промежуточные переменные
Dim Tmp_byte2 As Byte


Dim L_time(30) As Eram Word
Dim L_id As Eram Integer At 69
Dim Id_adr As Eram Byte At 71
Dim Koef_r As Eram Word
Dim Koef_i As Eram Word
Dim Koef_u As Eram Word

Dim Tport As Eram Byte


Const Запись_ds1307 = &HD0                                  ' Адрес записи в ОЗУ Ds1307
Const Чтение_ds1307 = &HD1                                  ' Адрес чтения из ОЗУ Ds1307

Const Const_год = 6                                         ' Регистр год Ds1307
Const Const_часы = 2                                        ' Регистр часы Ds1307
Const Const_месяц = 5                                       ' Регистр месяц Ds1307
Const Const_минуты = 1                                      ' Регистр минуты Ds1307
Const Const_секунды = 0                                     ' Регистр секунды Ds1307
Const Const_день_недели = 3                                 ' Регистр день_недели Ds1307
Const Const_число_месяца = 4                                ' Регистр число_месяца Ds1307

Const Const_настройка_ds1307 = 7                            ' Регистр для настройки Ds1307
Const Const_stop_часы = &B10000000                          ' Значение константы для остановки часов
Const Const_start_часы = &B00000000                         ' Значение константы для запуска часов
Const Const_разрешение_sout_ds1307 = &H90                   ' Значение константы для старта секундных импульсов

'===============================================================================
'            И С П О Л Ь З У Е М Ы Е     П О Д П Р О Г Р А М М Ы
'===============================================================================

Declare Sub Запись_i2c(byval Адрес_чипа_запись As Byte , Byval Регистр_чипа As Byte , Byval Записываемая_переменная As Byte)
Declare Sub Чтение_i2c(byval Адрес_чипа_чтение As Byte , Byval Адрес_чипа_запись As Byte , Byval Регистр_чипа As Byte , Считанная_переменная As Byte)
Declare Sub Copy_inputs_to_table
Declare Sub Modbus_exec
Declare Sub Set_usart_speed
Declare Sub Send_to_master                                  'подпрограмма передачи ответа мастеру
Declare Sub Error_modbus                                    'подпрограмма формирования ошибки модбас
Declare Sub Copy_data_to_table
Declare Sub Copy_log_to_table
Declare Sub Save_log
Declare Sub Mbpacage

' **************** выходы*************
'Config Portc.0 = Output
Config Portd.3 = Output
Config Portd.4 = Output
Config Portd.7 = Output
Config Pinc.0 = Input
Config Pinc.1 = Input
Config Pinb.0 = Input
Config Pinb.1 = Input
Config Pinb.2 = Input
Config Pind.5 = Input
Config Pinb.3 = Input
Config Pinb.4 = Input
Set Pinb.3
Set Pinb.4

'Test_light Alias Portc.0
Enable_tx Alias Portd.3                                     'разрешение на передачу по 485
Enable_rx Alias Portd.4                                     'разрешение на прием в двух проводке
'T1 Alias Portb.0
T2 Alias Portd.7
Tmreset Alias Pind.5
Set Tmreset
' ****************      0
'***************************************************************
' I/O configuration
Input_1 Alias Pinc.0                                        ' Input 1
Input_2 Alias Pinb.2                                        ' Input 2
Input_3 Alias Pinc.1                                        ' Input 3
Input_4 Alias Pinb.1                                        ' Input 4
Input_5 Alias Pinb.0                                        ' Input 5
'Input_6 Alias Pina.5                                        ' Input 6
'Input_7 Alias Pina.6                                        ' Input 7
'input_8 Alias Pina.7                                       ' Input 8
Set Input_1
Set Input_2
Set Input_3
Set Input_4
Set Input_5
Set Portd.6


Config Pind.2 = Input                                       ' Настраиваем вывод на вход
Config Int0 = Rising                                        ' Прерывание срабатывает по спаду уровня   Rising (по переднему фронту) ; Falling (по заднему фронту) ; Low Level (по низкому уровню)
On Int0 Прерывание_ds1307 Nosave                            ' После прерывания идем в подпрограмму обработки

Config Timer0 = Timer, Prescale = 256                       'организация задержки отключения разрешения передачи, при передаче на порт 485             '4000000 0,065536 сек (15,25878906 в 1 секунду)          8000000  0,032768 30,51757813

Set Portd.2

Enable_tx = 1

If Tport > 10 Then Tport = 9
If Tport = 0 Then Tport = 9
If Modbus_slave > 254 Then Modbus_slave = 1
If Modbus_slave = 0 Then Modbus_slave = 1



Illegal_function Alias 1
Illegal_data_address Alias 2
Illegal_data_value Alias 3

'---------------------- Настраиваем АЦП --------------------------------------------------
Config Adc = Single , Prescaler = 16 , Reference = Avcc

' Admux = &B00000110
'           ||||||||
'           |||||||+--- 0 - MUX0 - выбор входа АЦП для измерения
'           ||||||+---- 1 - MUX1 - выбор входа АЦП для измерения
'           |||||+----- 2 - MUX2 - выбор входа АЦП для измерения
'           ||||+------ 3 - MUX3 - выбор входа АЦП для измерения
'           |||+------- 4 - резерв
'           ||+-------- 5 - ADLAR - выравнивание результата измерения по левому краю
'           |+--------- 6 - REFS0 - выбор источника опорного напряжения
'           +---------- 7 - REFS1 - выбор источника опорного напряжения
Start Adc
Reset T2
Waitms 150
Set T2
Waitms 300
Reset T2
Waitms 150
Set T2
Waitms 300
Reset T2
Waitms 150
Set T2
Waitms 300
Reset T2
Waitms 150
Set T2
Waitms 300
Reset T2
Waitms 150
Set T2
Waitms 300
Reset T2
Waitms 500


'************************************************************
' Program initialisation
'************************************************************
' Config Portc = Output                                     'настроим порт с как выходы
Modc = 0                                                    'инициализация
W_to_device = 0
Error_mod = 0
Cnt_print = 0
Frame_value = Frame_value_dev
Load_timer = &H6C
If Frame_value = 255 Then Frame_value = 253


Call Set_usart_speed
Call Copy_inputs_to_table
Table_data(6) = Inputs
Tmpl_input = Table_data(6)

Load Timer0, Load_timer
On Timer0 Modbus_timers


' On Urxc Urxc_isr                                           'прерывание по приему UART
'
On Utxc Utxc_isr                                            'прерывание по передаче UART



'  On Urxc Usart_0_input_data_asm Nosave
'  Enable Urxc

'  Enable Timer0
'Start Timer0
'Enable Interrupts
Clear Serialin
Enable Timer0
Start Timer0
'\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
'--------------  Разрешаем работу необходимых прерываний  ----------------------
Enable Int0
'------------  Разрешаем работу всех включенных прерываний  --------------------
Enable Interrupts
'===============================================================================
'Clear Serialin
'резерв

'\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
'    З А П У С К    И    П Р Е Д В А Р И Т Е Л Ь Н Ы Е    Н А С Т Р О Й К И
'\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
'Читаем данные нулевого регистра Ds1307, если 7 бит равен 1, значит часы стоят

'Если часы стояли, запускаем
I2cstart
I2cwbyte &HD0
I2cwbyte Const_настройка_ds1307
I2cwbyte Const_разрешение_sout_ds1307
I2cstop


'Секунды = Read_ds1307(const_секунды)
I2cstart
I2cwbyte &HD0
I2cwbyte &H0
I2cstart
I2cwbyte &HD1
I2crbyte Секунды, Ack
I2crbyte Минуты, Ack
I2crbyte Часы, Ack
I2crbyte День_недели, Ack
I2crbyte Число_месяца, Ack
I2crbyte Месяц, Ack
I2crbyte Год, Nack
I2cstop

'Для симуляции в Протеусе всегда "0"
'If Tmreset = 0 Then
'Запускаем часы
Waitms 100
'    T1 = 1


Секунды = 1
Минуты = 0
Часы = 1
День_недели = 3
Число_месяца = 1
Месяц = 12
Год = 15

Table_data(16) = Секунды
Table_data(17) = Минуты
Table_data(18) = Часы
Table_data(19) = Число_месяца
Table_data(20) = Месяц
Table_data(21) = Год

Год = Makebcd(Год)                                          ' Год
Часы = Makebcd(часы)                                        ' Часы
Месяц = Makebcd(Месяц)                                      ' Месяц
Минуты = Makebcd(Минуты)                                    ' Минуты
Секунды = Makebcd(Секунды)                                  ' Секунды
День_недели = Makebcd(День_недели)                          ' День недели
Число_месяца = Makebcd(число_месяца)                        ' Число

Call Запись_i2c(Запись_ds1307, Const_секунды, Секунды)


Enable_rx = 1                                               '1- приемние включен , 0 - приемник выключен

'                   Г Л А В Н Ы Й         Ц И К Л
'===============================================================================
' Главный_цикл:
Do                                                          'начало основного цикла
    
    
  
    
    If W_to_device = 1 Then                                 'при наличии признака записи в устройство (уставки, настройки, выходыи т.д.)
        Select Case Beg_adr_w                               'при записи (функция 6) Beg_adr = индексу в массиве  Table_data
            
            Case 1:
                'адрес 4010 - номер устройства в сети модбас (читать писать)
                'запись в энергонезависимую память
                Tmp_byte = Low(Tmp_table_data(Beg_adr_w))
                If Tmp_byte > 0 And Tmp_byte < 255 Then
                    Modbus_slave = Tmp_byte
                    
                    Table_data(12) = Tmp_byte
                End If
            Case 2:
                Tmp_byte = Low(Tmp_table_data(Beg_adr_w))   ' адрес 4003 -  номер (читать писать)
                Serial_numb_l = Tmp_byte                    'запись в энергонезависимую память
                Tmp_byte = High(Tmp_table_data(Beg_adr_w))
                Serial_numb_h = Tmp_byte
                Table_data(3) = Tmp_table_data(Beg_adr_w)   'запись в таблицу

            Case 3
                Секунды = Low(Tmp_table_data(Beg_adr_w))
                Секунды = Makebcd(Секунды)
                Call Запись_i2c(Запись_ds1307, Const_секунды, Секунды)
            Case 4
                Минуты = Low(Tmp_table_data(Beg_adr_w))
                Минуты = Makebcd(Минуты)
                Call Запись_i2c(Запись_ds1307, Const_минуты, Минуты)
            Case 5
                Часы = Low(Tmp_table_data(Beg_adr_w))
                Часы = Makebcd(часы)
                Call Запись_i2c(Запись_ds1307, Const_часы, Часы)
            Case 6
                Число_месяца = Low(Tmp_table_data(Beg_adr_w))
                Число_месяца = Makebcd(число_месяца)
                Call Запись_i2c(Запись_ds1307, Const_число_месяца, Число_месяца)
            Case 7
                Месяц = Low(Tmp_table_data(Beg_adr_w))
                Месяц = Makebcd(Месяц)
                Call Запись_i2c(Запись_ds1307, Const_месяц, Месяц)
            Case 8
                Год = Low(Tmp_table_data(Beg_adr_w))
                Год = Makebcd(Год)
                Call Запись_i2c(Запись_ds1307, Const_год, Год)
                
            Case 10:
                Tmp_byte = Tmp_table_data(Beg_adr_w)
                If Tmp_byte > 0 And Tmp_byte < 6 Then
                    Usart_speed = Tmp_byte
                    Call Set_usart_speed
                End If
            Case 11:
                Tmp = Tmp_table_data(Beg_adr_w)
                If Tmp > 0 And Tmp < 20000 Then
                    Koef_r = Tmp
                    
                End If
            Case 12:
                Tmp = Tmp_table_data(Beg_adr_w)
                If Tmp > 0 And Tmp < 20000 Then
                    Koef_i = Tmp
                    
                End If
            Case 13:
                Tmp = Tmp_table_data(Beg_adr_w)
                If Tmp > 0 And Tmp < 20000 Then
                    Koef_u = Tmp
                    
                End If
            Case 14:
                Tmp = Tmp_table_data(Beg_adr_w)
                If Tmp > 0 And Tmp < 10 Then
                    Tport = Tmp
                    
                End If
        End Select
        W_to_device = 0
    End If
    
    
    
    
    Call Copy_inputs_to_table
    
    
    
    If Флаг_опросить_ds1307 <> 0 Then
        T2 = Not T2
        I2cstart
        I2cwbyte &HD0
        I2cwbyte &H0
        I2cstart
        I2cwbyte &HD1
        I2crbyte Секунды, Ack
        I2crbyte Минуты, Ack
        I2crbyte Часы, Ack
        I2crbyte День_недели, Ack
        I2crbyte Число_месяца, Ack
        I2crbyte Месяц, Ack
        I2crbyte Год, Nack
        I2cstop
        Год = Makedec(Год)                                  ' Год
        Часы = Makedec(часы)                                ' Часы
        Месяц = Makedec(Месяц)                              ' Месяц
        Минуты = Makedec(Минуты)                            ' Минуты
        Секунды = Makedec(Секунды)                          ' Секунды
        День_недели = Makedec(День_недели)                  ' День недели
        Число_месяца = Makedec(число_месяца)                ' Число
        
        Флаг_опросить_ds1307 = 0
        

    End If
    '===============================================================
    Waitms 1
    ' время последней сработавшей защиты
    If Tmpl_input <> Inputs Then
        Call Save_log
    End If
    '=========================================================
    
    Idle
    'nop
    
    
Loop

'-----------------------------------------------------------------------

'-----------------------------------------------------------------------
Utxc_isr:
'Подпрограмма передачи данных
If Cnt_print = 1 Then                                       ' если последний байт передан
    Enable_tx = 1                                           '  (запрещаем передачу )
    Enable_rx = 1                                           ' разрешаем прием
    Cnt_print = 0                                           ' обнуляем признак последнего байта передачи
    Disable Utxc                                            ' запреаем прерывание.
    ' Enable Int0
End If

Return
'-----------------------------------------------------------------------

Sub Send_to_master()
    '    Disable Int0
    '  Disable Urxc
    Enable Utxc                                             'разрешаем прерывание по
    If Enable_tx = 1 Then
        Enable_tx = 0                                       ' разрешаем  передачу )
        Enable_rx = 0                                        'запрещаем прием
        For I = 1 To N_byte                                 'ответ мастеру.  цикл для передачи буфера обмена с заданным кол. байт c заданного адреса
            Print Chr(Mbuf(I));                             'отправка буфера обмена в Нех
        Next
        ' Print N_byte ;
        Cnt_print = 1
    End If
    '   Enable Urxc
End Sub
'-----------------------------------------------------------------------

Sub Error_modbus()
    Mbuf(1) = Modbus_slave                                  'функция формирования пакета исключительного ответа мастеру по ошибке.
    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
Call Modbus_exec                                            'останавливаем прерывание по таймеру тишины между фреймами
' Md_t_start = 1                                           'выставляем признак того, что в буфере принят фрейм
Return

'-----------------------------------------------------------------------
Sub Copy_log_to_table()
    Disable Interrupts
    Local Tmprd As Word
    For I = 1 To 30
        Tmprd = L_time(I)
        Table_data(I) = Tmprd
    Next                                                    ' = Число_месяца
    Enable Interrupts
End Sub

'-------------------------------------------------------------------------
Sub Save_log()
    Local Tid As Byte
    Local Tmpid As Word
    Disable Interrupts
    
    Waitms 20
    
    Tid = Id_adr
    If Tid > 29 Then Tid = 0

    If Tid > 25 Then
        Tid = 0
    End If

    
    Incr Tid
    Tmpid = Makeint(Секунды, Минуты)
    
    
    L_time(Tid) = Tmpid
    Incr Tid
    Tmpid = Makeint(часы, Число_месяца)
    L_time(Tid) = Tmpid
    Incr Tid                                                ' = Секунды
    Tmpid = Makeint(Месяц, Год)
    L_time(Tid) = Tmpid
    Incr Tid                                                ' = Минуты
    Tmpid = Inputs
    Tmpl_input = Inputs
    L_time(Tid) = Tmpid
    Incr Tid
    ' = Часы
    Tmpid = L_id
    Incr Tmpid
    If Tmpid > 65534 Then Tmpid = 0
    L_time(Tid) = Tmpid
    L_id = Tmpid
    Id_adr = Tid                                            ' = Число_месяца
    Enable Interrupts
End Sub

'-----------------------------------------------------------------------------

Sub Copy_data_to_table()
    

    Tmp_byte = Modbus_slave                                 ' нельзя писать ерам байт в инт. можно через промежуточную переменную
    Table_data(12) = Tmp_byte                               ' адрес 4010 - номер устройства в сети модбас (читать писать)
    Table_data(13) = Ust1_up                                ' адрес 4011 - уставка верх  (читать писать)
    Table_data(14) = Ust1_dwn                               ' адрес 4012 - уставка низ (читать писать)
    Table_data(15) = Frame_value                            ' адрес 4015 - значение TIMER0 загружаемое при старте таймера TIMER0 (читать)
    Tmp_byte = Serial_numb_h
    Tmp_byte2 = Serial_numb_l
    'серийный номер
    Table_data(3) = Makeint(Tmp_byte2, Tmp_byte)
    Table_data(4) = &H8                                     ' весия Прошивки ( 02)
    Table_data(5) = 660                                     't константа (660 или 2140)
    Table_data(7) = &HFFFF                                  'ток  Imax амплитудное значение  (нету - код FFFF)
    ' Table_data(8) = &HFFFF                                 'напряжение  (нету - код FFFF)
    Table_data(9) = &HFFFF                                  'сопротивление  (нету - код FFFF)
    Table_data(10) = &HFFFF                                 'наппряжение батарейки
    Tmp_byte = Tport
    Table_data(11) = Tmp_byte
    Table_data(16) = Секунды
    Table_data(17) = Минуты
    Table_data(18) = Часы
    Table_data(19) = Число_месяца
    Table_data(20) = Месяц
    Table_data(21) = Год
    
    Tmp = L_id
    Table_data(22) = Tmp
    
    Tmp = Koef_i
    If Tmp > 20000 Or Tmp = 0 Then Koef_i = 1000
    Tmp = Koef_r
    If Tmp > 20000 Or Tmp = 0 Then Koef_r = 1000
    Tmp = Koef_u
    If Tmp > 20000 Or Tmp = 0 Then Koef_u = 1078
    
    Table_data(23) = Koef_r
    Table_data(24) = Koef_i
    Table_data(25) = Koef_u
    
End Sub



Sub Copy_inputs_to_table()
    Tmp_byte2 = Tport
    
    
    Table_data(26) = 0
    Table_data(27) = 0
    Table_data(28) = 0
    Table_data(29) = 0
    Table_data(30) = 0
    
    
    
    
    
    For I = 0 To 9
        If Input_1 = 0 Then Incr Table_data(26)
        If Input_2 = 0 Then Incr Table_data(27)
        If Input_3 = 0 Then Incr Table_data(28)
        If Input_4 = 0 Then Incr Table_data(29)
        If Input_5 = 0 Then Incr Table_data(30)
        Waitus 400
    Next
    
    If Table_data(26) > Tmp_byte2 Then Inputs 0.0 = 0 Else Inputs 0.0 = 1
    If Table_data(27) > Tmp_byte2 Then Inputs 0.1 = 0 Else Inputs 0.1 = 1
    If Table_data(28) > Tmp_byte2 Then Inputs 0.2 = 0 Else Inputs 0.2 = 1
    If Table_data(29) > Tmp_byte2 Then Inputs 0.3 = 0 Else Inputs 0.3 = 1
    If Table_data(30) > Tmp_byte2 Then Inputs 0.4 = 0 Else Inputs 0.4 = 1
    
    Table_data(26) = 0
    Table_data(27) = 0
    Table_data(28) = 0
    Table_data(29) = 0
    Table_data(30) = 0
    
    Inputs 0.5 = 1
    Inputs 0.6 = 1
    Inputs 0.7 = 0
    
    
End Sub

'-----------------------------------------------------------------------


'===============================================================================
Sub Запись_i2c(ByVal Адрес_чипа_запись As Byte, ByVal Регистр_чипа As Byte, ByVal Записываемая_переменная As Byte)
    '-------------------------------------------------------------------------------
    I2cstart                                                ' Подготовка к работа шины I2c
    I2cwbyte Адрес_чипа_запись                              ' Адресное обращение к используемому чипу i2c, для записи
    I2cwbyte Регистр_чипа                                   ' Адрес регистра, в который будет производиться запись
    I2cwbyte Записываемая_переменная                        ' Записываемая переменная
    I2cstop                                                 ' Освобождаем шину I2c
    '-------------------------------------------------------------------------------
    Waitms 10
End Sub
'===============================================================================


'===============================================================================
'  Подпрограмма для обработки прерывания инициируемого секундными импульсами с вывода "SQW/OUT" Ds1307
'=================<===<=<=<=<===<===<=<=<=<=====================================
Прерывание_ds1307: ' с помощью ASM AVR
'-------------------------------------------------------------------------------
$asm
push R16                                                    ' Время выполнения инструкции, 2 такта
ldi R16, 1                                                  ' Загрузить константу, время выполнения инструкции, 1 такт
sts {Флаг_опросить_ds1307} , R16                            ' Загрузить значение регистра в переменную, время выполнения инструкции, 2 такта
Pop R16                                                     ' Время выполнения инструкции, 2 такта
reti                                                        ' Время выполнения инструкции, 4 такта
$end Asm
'-------------------------------------------------------------------------------
Return
'===============================================================================




Sub Set_usart_speed()
    Local Tmpbyte As Byte
    Tmpbyte = Usart_speed
    Select Case Tmpbyte
        Case 1
            Baud = 4800
            Ubrr = 103
            Ucsra.u2x = 0
            Load_timer = &H36                               '255-56=199 = 56=&H36
        Case 2
            Baud = 9600
            Ubrr = 51
            '       Ubrrh = 0                                         ';
            ' Ubrrl = 51                                              ';//9600
            Ucsra.u2x = 0
            Load_timer = &H9C                               '9c=156   255-156 = 99
        Case 3
            Baud = 19200
            Ubrr = 25
            Ucsra.u2x = 0
            Load_timer = &HCD                               '255- 205=50  205=cd
        Case 4
            Baud = 38400
            Ubrr = 12
            Ucsra.u2x = 0
            Load_timer = &HE6                               '255-230=25   =e6
            
        Case Else
            Baud = 9600
            '     Ubrr = 51
            Ubrrh = 0                                       ';
            Ubrrl = 51                                      ';//9600
            Ucsra.u2x = 0
            Load_timer = &H9C
            
            
    End Select
    '  T1 = 1
    T2 = 1
    Waitms 100
    'Config Com1 = Baudrate , Synchrone = 0 , Parity = None , Stopbits = 2 , Databits = 8 , Clockpol = 0
    
End Sub


'-------------------------------------------------------------------------------------------------------------------------------------------

Serial0bytereceived:
Load Timer0, Load_timer
Start Timer0
Return


'-------------------------------------------------------------------------------------------------------------------------------------------
Sub Modbus_exec()
    Local Tmpdates As Long
    Local Tmp_a As Word
    Local A As Byte
    
    Disable Int0
    Modc = 0
    
M1:
    A = Ischarwaiting()
    If A = 1 Then
        Incr Modc
        Inputbin Modt
        Mbuf(Modc) = Modt
        If Modc > 16 Then GoTo M0
    Else
        GoTo M0
    End If
    GoTo M1
M0:
    
    
    Enable Int0
    
    Clear Serialin
    
    
    '=======================обработка пакета=============================
    '  если время между принятыми байтами больше 3.5 символа, в буфере принят фрейм
    
    Error_mod = 0                                           ' обнуляем ошибку и начинаем разбирать принятый фрейм из буфера.
    'T2 = 1
    If Mbuf(1) = Modbus_slave And Modc > 0 Then             'первый байт это адрес устройства    Or Mbuf(1) = 0 And Modc > 0
        
        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- чтение регистров
                    Call Copy_data_to_table                 'копируем дискретные входа и информацию в таблицу Модбас для вывота
                    Tmpdates = Getadc(2)
                    
                    Tmpdates = 1023 - Tmpdates
                    
                    Tmpdates = Tmpdates * 5000
                    Tmpdates = Tmpdates / 1024
                    Tmp = Koef_r
                    Tmpdates = Tmpdates * Tmp
                    Tmpdates = Tmpdates / 1000
                    Table_data(9) = Tmpdates                ' I 10ma утечка
                    
                    Tmpdates = 0
                    
                    
                    For I = 0 To 19
                        Tmp_a = Getadc(6)
                        Tmpdates = Tmpdates + Tmp_a
                        Waitus 200
                    Next I
                    
                    Tmpdates = Tmpdates / 20
                    Tmpdates = Tmpdates * 5
                    Tmpdates = Tmpdates * 1000
                    Tmpdates = Tmpdates / 1023
                    Tmp = Koef_u
                    Tmpdates = Tmpdates * Tmp
                    Tmpdates = Tmpdates / 1000
                    Table_data(8) = Tmpdates                ' Umax напряжение Питания (амплитудное)
                    
                    Tmpdates = 0
                    For I = 0 To 120
                        Tmp_a = Getadc(7)
                        If Tmp_a > Tmpdates Then Tmpdates = Tmp_a
                        If I > 100 And Tmp_a < 15 Then Exit For
                        Waitus 100
                    Next I
                    
                    Tmpdates = Tmpdates * 5
                    Tmpdates = Tmpdates * 1000
                    
                    Tmpdates = Tmpdates / 1024
                    'Tmpdates = Tmpdates * 100
                    '  Tmpdates = Tmpdates / 141
                    Tmp = Koef_i
                    Tmpdates = Tmpdates * Tmp
                    Tmpdates = Tmpdates / 1000
                    Table_data(7) = Tmpdates                ' ток Imax амплитудное значение
                    
                    Call Copy_inputs_to_table
                    Table_data(6) = Inputs
                    Call Mbpacage
                    
                Case 4:                                     '4- функция чтение регистров журнала событий
                    
                    Call Copy_log_to_table
                    'формируем пакет Модбас
                    Call Mbpacage
                    
                Case 6:                                     'функция 6- запись одного регистра
                    Tmp_table_data(Beg_adr) = Makeint(Mbuf(6), Mbuf(5))        'записываем полученное значение
                    W_to_device = 1                         'формируем признак записи в устройство
                    Beg_adr_w = Beg_adr                     'номер слова для записи в память
                    N_byte = 8
                    'длина посылки для функции 6 всегда =8 байт
                    If Beg_adr_w > 14 Then Error_mod = Illegal_data_address       'неправильный адрес регистра ( нельзя писать)

                Case Else:
                    Error_mod = Illegal_function            'неподдерживаемая функция
                    
            End Select
            '----------------------------------обработка ошибок------------------------------------------------------
            If Error_mod > 0 Then
                Call Error_modbus                           'код ошибки неправильный функциональный код
                '            T1 = 1                                   'ответ мастеру
                '  Waitms 300
                '  T1 = 0
            End If
            
            Call Send_to_master                             'ответ мастеру
            
        Else                                                'если неправильная контрольная сумма
            Error_mod = 3                                   'код ошибки Checksumme
            '   Call Error_modbus
            '   Call Send_to_master
            '    T1 = 1                                             'ответ мастеру
            '    Waitms 100
            '    T1 = 0
            ' T2 = 0
        End If
    End If
    Modc = 0
    Md_t_start = 0                                          ' обнуляем все признаки
    'End If
    
End Sub



Sub Mbpacage()
    
    N_word = Makeint(Mbuf(6), Mbuf(5))                      'количество слов чтения
    If N_word > Maximum_input_registers Then                'я ограничил количество 27 словами
        N_word = 1                                          ' формируем ошибку если в запросе на чтение больше 27 слов
        Error_mod = Illegal_data_address                    'если превышение размера буфера то формируем ошибку 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
End Sub

в протеусе при эмуляции все замечательно работает
НО собрал в железяку и пошли глюки

при непрерывном  обмене данными с ПК иногда происходит кратковременное "подвисание" контроллера- не отвечает на запрос и в этот момент происходит запись в ЕЕПРОМ произвольных данных с дискретных входов ( входа все  посадил на землю а на них всеравно якобы есть 1)
тоесть
сначала читаю состояние портов в переменную Inputs

Copy_inputs_to_table

Sub Copy_inputs_to_table()
     Tmp_byte2 = Tport

     Table_data(26) = 0
     Table_data(27) = 0
     Table_data(28) = 0
     Table_data(29) = 0
     Table_data(30) = 0



     For I = 0 To 9
         If Input_1 = 0 Then Incr Table_data(26)
         If Input_2 = 0 Then Incr Table_data(27)
         If Input_3 = 0 Then Incr Table_data(28)
         If Input_4 = 0 Then Incr Table_data(29)
         If Input_5 = 0 Then Incr Table_data(30)
                 Waitus 400
     Next

     If Table_data(26) > Tmp_byte2 Then Inputs.0 = 0 Else Inputs.0 = 1
     If Table_data(27) > Tmp_byte2 Then Inputs.1 = 0 Else Inputs.1 = 1
     If Table_data(28) > Tmp_byte2 Then Inputs.2 = 0 Else Inputs.2 = 1
     If Table_data(29) > Tmp_byte2 Then Inputs.3 = 0 Else Inputs.3 = 1
     If Table_data(30) > Tmp_byte2 Then Inputs.4 = 0 Else Inputs.4 = 1

     Table_data(26) = 0
     Table_data(27) = 0
     Table_data(28) = 0
     Table_data(29) = 0
     Table_data(30) = 0

    Inputs.5 = 1
    Inputs.6 = 1
    Inputs.7 = 0

End Sub

затем сравниваю со старым состоянием порта
    If Tmpl_input <> Inputs Then
       

и занисываю  Call Save_log в ЕЕПРОМ

Sub Save_log

Sub Save_log()
    Local Tid As Byte
    Local Tmpid As Word
    Disable Interrupts
   
    Waitms 20
   
    Tid = Id_adr
    If Tid > 29 Then Tid = 0

    If Tid > 25 Then
        Tid = 0
    End If

   
    Incr Tid
    Tmpid = Makeint(Секунды, Минуты)
   
   
    L_time(Tid) = Tmpid
    Incr Tid
    Tmpid = Makeint(часы, Число_месяца)
    L_time(Tid) = Tmpid
    Incr Tid                                                ' = Секунды
    Tmpid = Makeint(Месяц, Год)
    L_time(Tid) = Tmpid
    Incr Tid                                                ' = Минуты
    Tmpid = Inputs
    Tmpl_input = Inputs
    L_time(Tid) = Tmpid
    Incr Tid
    ' = Часы
    Tmpid = L_id
    Incr Tmpid
    If Tmpid > 65534 Then Tmpid = 0
    L_time(Tid) = Tmpid
    L_id = Tmpid
    Id_adr = Tid                                            ' = Число_месяца
    Enable Interrupts
End Sub

и запоминаю Inputs во временную переменную     Tmpl_input = Inputs
и в момент когда "подвисает" связь в переменных  Tmpl_input  и  Inputs находится всякий бред
в результате чего даже при все время замкнутых входах на землю в лог  пишутся разные  значения

мозг взорвался думать уже нечем, но есть подозрения что набокопорил  с
$hwstack = 80
$swstack = 96
$framesize = 80
и огромным количеством переменных

Отредактировано Penumbra (2016-07-12 23:48:56)

0

2

Если есть опасения,что неправильная работа программы зависит от неверной конфигурации стека можно попробовать поискать по форуму как рассчитать размер стека.Где-то здесь я наталкивался на такую инфу.
Вот немного,где взял не помню.

стек

Аппаратный стек
Описывает количество байт, отведенных для аппаратного стека. Когда вы используете команды CALL или GOSUB в стеке запоминаются по два байта.
Когда вы используете две команды GOSUB, в стеке запоминаются 4 байта. Некоторые из инструкций также используют стек. При использовании прерываний в стеке сохраняется 32 байта.
Программный стек
Описывает размер программного стека.
Каждая локальная переменная использует 2 байта. Каждая переменная, используемая в подпрограмме, также использует 2 байта. Если вы использовали 10 переменных в подпрограмме и 3 параметра было передано в подпрограмму, то вам необходимо:
13 * 2 = 26 байт
Размер фрейма
Описывает размер фрейма
Каждая локальная переменная запоминается в области памяти, которая называется 'фрейм'
Когда вы имеете 2 локальных переменных и символьную переменную длиной 10 символов, необходим фрейм размером (2*2) + 11 = 15 байт
Также фрейм используют подпрограммы конвертации типов переменных, такие как STR() или VAL() и подобные им. Это бывает, когда вы используете команды INPUT [числовая переменная] или PRINT [числовая переменная]
При это используется не более 16 байт памяти фрейма. Т.е, в нашем случае получим наилучшее значение размера фрейма равное 15+16 = 31 байт

Отредактировано Sergik07 (2016-07-13 10:48:28)

0

3

а у вас точно "Stopbits = 2" с стороны компа 2 бита стоповых?

0

4

Sergik07 ок сейчас попробую
RDW да 2 стоповых бита

0

5

Исключите глюки железа. Свяжите Протеус с компом и посмотрите, будет-ли глючить.

0


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » atmega8 и usart глюки в железе но работает в протейсе, гдето напортач