$regfile = "m48pdef.dat"
$crystal = 1000000
$framesize = 128
$hwstack = 128
$swstack = 128
'===============================================================================
' Включение / выключение питания аппаратных модулей МК
'===============================================================================
Prr = &B_1011_1000
' |||| ||||
' |||| |||+--- 0 - PRADC - если 1, то модуль ADC (АЦП) выключен
' |||| ||+---- 1 - PRUSART0 - если 1, то модуль USART выключен
' |||| |+----- 2 - PRSPI - если 1, то модуль SPI выключен
' |||| +------ 3 - PRTIM1 - если 1, то Timer1/Counter1 выключен
' |||+-------- 4 - PRUSART1 - если 1, то модуль USART1 выключен
' ||+--------- 5 - PRTIM0 - если 1, то Timer0/Counter0 выключен
' |+---------- 6 - PRTIM2 - если 1, то Timer2/Counter2 выключен
' +----------- 7 - PRTWI - если 1, то модуль TWI (I2c) выключен, после включени обязательна повторная инициализация
'===============================================================================
' Н А С Т Р О Й К А TIMER2 софтовые часы
'===============================================================================
Config Timer2 = Timer , Async = On , Prescale = 128 ' Делитель 32768 / 128 / 256 = 1 сек (прерывание TIMER2 = 1 раз в секунду)
'Ссылка на подпрограмму обработчика прерывания TIMER2, для работы часов
On Timer2 Обработка_прерывания_timer2 Nosave ' Ссылка на подпрограмму обработчика прерывания TIMER2
Stop Timer2
Timer2 = 0
'--------------- Настройка пониженного энергопотребления МК ------------------
Assr.3 = 1 : Waitms 100 ' Включить НЧ-генератор AS2 и подождать стабилизации амплитуды генератора
'При включении бита AS2 (3) в регистре ASSR (ASSR.3), становится возможным применение режима
'"Powersave" - разновидность спящего режима. Пробуждение МК от TIMER2
'===============================================================================
' Н А С Т Р О Й К А Ds18b20
'===============================================================================
Port_ds18x20 Alias Pinc
Vcc_ds18b20 Alias Portc.1 : Config Vcc_ds18b20 = Output : Vcc_ds18b20 = 0
Const Const_подготов_чтения_ds18x20 = &HCC
Const Const_запуск_измерения_ds18x20 = &H44
Const Const_чтение_температуры_ds18x20 = &HBE
Dim Порядковый_номер_ds18x20 As Byte
Dim Температура_integer As Integer ' Температура * 16, в HEX формате
Dim Сырые_данные_ds18x20(9) As Byte At Температура_integer Overlay ' Массив данных полученных от Ds18b20
Dim Готов_темпер_ds18b20_int As Integer
Dim Готов_темп_ds18b20_low_byte As Byte At Готов_темпер_ds18b20_int Overlay
Dim Готов_темп_ds18b20_high_byte As Byte At Готов_темпер_ds18b20_int + 1 Overlay
Dim Счетчик_измерений_long As Long
Dim Счетчик_измерений_low_byte As Byte At Счетчик_измерений_long Overlay
Dim Счетчик_измерений_1_high_byte As Byte At Счетчик_измерений_long + 1 Overlay
Dim Счетчик_измерений_2_high_byte As Byte At Счетчик_измерений_long + 2 Overlay
Dim Счетчик_измерений_3_high_byte As Byte At Счетчик_измерений_long + 3 Overlay
Dim Температура_single As Single
Dim Not_used_1_str As String * 10 'Без этой переменной бывает портится следующая за Single
Dim Готов_темпер_ds18b20_sin As Single
Dim Not_used_2_str As String * 10 'Без этой переменной бывает портится следующая за Single
'===============================================================================
' Н А С Т Р О Й К А Nrf24L01
'===============================================================================
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 1
'Программное обеспечение SPI НЕ работает с nRF24L01, используйте оборудование SPI только, но эсэсовцы pin-код должен управляться нашей функцией
Ce_nrf24l01 Alias Portb.1 : Config Ce_nrf24l01 = Output 'CE pin is output
Csn_nrf24l01 Alias Portb.2 : Config Csn_nrf24l01 = Output 'SS pin is output
Irq_nrf24l01 Alias Pind.2 : Config Irq_nrf24l01 = Input 'IRQ pin is input
'Инициализация аппаратного SPI
Spiinit
'Подключение питания Nrf24L01, коммутация транзистором BC807 (p-n-p), активный уровень "0"
On_vcc_nrf24l01 Alias 0
Off_vcc_nrf24l01 Alias 1
Vcc_nrf24l01 Alias Portb.0 : Config Vcc_nrf24l01 = Output : Vcc_nrf24l01 = Off_vcc_nrf24l01
'Подключение светодиода индикации передачи Nrf24L01, коммутация выводом МК, активный уровень "1"
On_led_nrf24l01 Alias 1
Off_led_nrf24l01 Alias 0
Led_txd_nrf24l01 Alias Portc.5 : Config Led_txd_nrf24l01 = Output : Led_txd_nrf24l01 = 0
Dim Number_transmitter As Byte : Number_transmitter = 4 'Номер передатчика (max = 5 с одним адресом)
Dim Frequency_transmitter As Byte : Frequency_transmitter = 100 'Итоговая частота = 2400 + Frequency_transmitter
Const En_aa = &H01
Const Rf_ch = &H05
Const Status = &H07
Const Tx_addr = &H10
Const Flush_tx = &HE1
Const Rf_setup = &H06
Const Write_reg = &H20
Const En_rxaddr = &H02
Const Rx_addr_p0 = &H0A
Const Config_nrf = &H00
Const Wr_tx_pload = &HA0
Dim Txd_byte(35) As Byte
Declare Sub Write_register(byval Copy_amount_byte As Byte)
'===============================================================================
' Н А С Т Р О Й К А АЦП
'===============================================================================
Const Опорное_aref = &B_0000_0000
Const Опорное_avcc = &B_0100_0000
Const Опорное_internal_1_1v = &B_1100_0000
Const Channel_temperature = &B_0000_1000
Const Channel_internal_1_1v = &B_0000_1110
Const Channel_gnd_0v = &B_0000_1111
'SM2 SM1 SM0 Sleep Mode
' 0 0 0 Idle
' 0 0 1 ADC Noise Reduction
' 0 1 0 Power-down
' 0 1 1 Power-save
' 1 0 0 Reserved
' 1 0 1 Reserved
' 1 1 0 Standby(1)
'&B_0000_0000
' ||||
' ||||
' |||+-------- Bit 0 – SE: Sleep Enable
' ||+--------- Bit 1 – SM0: Sleep Mode Select Bit 0
' |+---------- Bit 2 – SM1: Sleep Mode Select Bit 1
' +----------- Bit 3 – SM2: Sleep Mode Select Bit 2
'
Const Значение_idle = &B_0000_0001
Const Значение_adcnoise = &B_0000_0011
Const Значение_powersave = &B_0000_0111
Const Значение_powerdown = &B_0000_0101
Config Adc = Single , Prescaler = 128 , Reference = Avcc
Start Adc
On Adc Обработка_прерывания_ацп Nosave
'Формула расчёта: 1024 * 0,99...1,21 = 1013,76...1239,04
'Реальный МК Atmega328P
'Const Const_коэффициент_перещета_1_1v = 1097.5 'Зависит от конкретного экземпляра МК, т.к., согласно документации 1.1V ± 10%, т.е., 1...1.2V
'Реальный МК Atmega328P
Const Const_коэффициент_перещета_1_1v = 1090 'Зависит от конкретного экземпляра МК, т.к., согласно документации 1.1V ± 10%, т.е., 1...1.2V
Dim Флаг_критический_разряд As Byte
Dim Temp_ацп_avcc_word As Word : Temp_ацп_avcc_word = 0
Dim Данные_ацп_avcc_word As Word : Данные_ацп_avcc_word = 0
Dim Vcc_txd_nrf24l01_word As Word
Dim Vcc_txd_nrf24l01_low_byte As Byte At Vcc_txd_nrf24l01_word Overlay
Dim Vcc_txd_nrf24l01_high_byte As Byte At Vcc_txd_nrf24l01_word + 1 Overlay
Dim Vcc_txd_nrf24l01_sin As Single
Dim Flag_передать_данные As Byte
Dim Timer_nrf24l01_sec As Byte : Timer_nrf24l01_sec = 30
Dim Timer_nrf24l01_min As Byte : Timer_nrf24l01_min = 0
Dim Timer_nrf24l01_hour As Byte : Timer_nrf24l01_hour = 0
Dim Timer_sec As Byte : Timer_sec = 30
Dim Timer_min As Byte : Timer_min = 0
Dim Timer_hour As Byte : Timer_hour = 0
Dim Val_timer_sec As Byte : Val_timer_sec = 30
Dim Val_timer_min As Byte : Val_timer_min = 0
Dim Val_timer_hour As Byte : Val_timer_hour = 0
Dim Flag_update_time As Byte
'-------------- Разрешаем работу необходимых прерываний ----------------------
Enable Adc
Enable Timer2
Start Timer2
'------------ Разрешаем работу всех включенных прерываний --------------------
Enable Interrupts
'===============================================================================
' Запуск и предварительная настройка
'===============================================================================
Adcsra.aden = 1 'Включаем АЦП
Gosub Измерение_avcc
Gosub Опрос_ds18x20
Gosub Передать_данные_nrf24l01
'===============================================================================
' Г Л А В Н Ы Й Ц И К Л
Главный_цикл:
'===============================================================================
If Timer_hour = 0 And Timer_min = 0 And Timer_sec = 1 Then
Vcc_ds18b20 = 1
Gosub Запуск_измерения_ds18x20
End If
If Timer_hour = 0 And Timer_min = 0 And Timer_sec = 0 Then
Gosub Опрос_ds18x20
Vcc_ds18b20 = 0
Счетчик_измерений_long = Счетчик_измерений_long + 1
Prr = &B_1011_1010
' |||| ||||
' |||| |||+--- 0 - PRADC - если 1, то модуль ADC (АЦП) выключен
' |||| ||+---- 1 - PRUSART0 - если 1, то модуль USART выключен
' |||| |+----- 2 - PRSPI - если 1, то модуль SPI выключен
' |||| +------ 3 - PRTIM1 - если 1, то Timer1/Counter1 выключен
' |||+-------- 4 - PRUSART1 - если 1, то модуль USART1 выключен
' ||+--------- 5 - PRTIM0 - если 1, то Timer0/Counter0 выключен
' |+---------- 6 - PRTIM2 - если 1, то Timer2/Counter2 выключен
' +----------- 7 - PRTWI - если 1, то модуль TWI (I2c) выключен, после включени обязательна повторная инициализация
' Примечание:
Ddrb = &B_1111_1111 : Portb = &B_0000_0001
Ddrc = &B_1111_1111 : Portc = &B_0000_0000
Ddrd = &B_1111_1011 : Portd = &B_0000_0000
'Ucsr0b.rxen0 = 1 'Включаем приёмник USART
'Ucsr0b.txen0 = 1 'Включаем передатчик USART
Adcsra.aden = 1 'Включаем АЦП
' Waitms 250 '250 'Ждём, пока запустится источник внутреннего опорного напряжения 1.1V
Gosub Измерение_avcc
' Print ""
' Print Счетчик_измерений_long
' Print Vcc_txd_nrf24l01_word
' Print Готов_темпер_ds18b20_sin
' Print Готов_темпер_ds18b20_int
' Print ""
Timer_sec = Val_timer_sec
Timer_min = Val_timer_min
Timer_hour = Val_timer_hour
Gosub Передать_данные_nrf24l01
Gosub Выключаем_все_ненужное
Flag_передать_данные = 0
End If
!ldi R16 , Значение_powersave 'Выставляем, как будем спать
!sts SMCR , R16 'Пишем в региср
!sleep 'Отправляемся спать
'===============================================================================
Goto Главный_цикл
End
'===============================================================================
'===============================================================================
Выключаем_все_ненужное:
'-------------------------------------------------------------------------------
Ucsr0b.rxen0 = 0 'Выключаем приёмник USART
Ucsr0b.txen0 = 0 'Выключаем передатчик USART
'Выключаем АЦП, слишком много потребляет 'Bit 7 – ADEN: ADC Enable / Disable
Adcsra.aden = 0
'Выключаем компаратор Bit 7 – ACD: Analog Comparator Disable
Acsr.acd = 0
Prr = &B_1011_1111
' |||| ||||
' |||| |||+--- 0 - PRADC - если 1, то модуль ADC (АЦП) выключен
' |||| ||+---- 1 - PRUSART0 - если 1, то модуль USART выключен
' |||| |+----- 2 - PRSPI - если 1, то модуль SPI выключен
' |||| +------ 3 - PRTIM1 - если 1, то Timer1/Counter1 выключен
' |||+-------- 4 - PRUSART1 - если 1, то модуль USART1 выключен
' ||+--------- 5 - PRTIM0 - если 1, то Timer0/Counter0 выключен
' |+---------- 6 - PRTIM2 - если 1, то Timer2/Counter2 выключен
' +----------- 7 - PRTWI - если 1, то модуль TWI (I2c) выключен, после включени обязательна повторная инициализация
' Примечание:
Ddrb = &B_1111_1111 : Portb = &B_0000_1001
Ddrc = &B_1111_1111 : Portc = &B_0000_0000
Ddrd = &B_1111_1011 : Portd = &B_0000_0000
'-------------------------------------------------------------------------------
Return
'===============================================================================
'===============================================================================
Setup_tx:
'-------------------------------------------------------------------------------
Txd_byte(1) = Write_reg + Tx_addr
Txd_byte(2) = &HD2
Txd_byte(3) = &HF0
Txd_byte(4) = &HF0
Txd_byte(5) = &HF0
Txd_byte(6) = &HF0
Call Write_register(6)
Txd_byte(1) = Write_reg + Rx_addr_p0
Txd_byte(2) = &HD2
Txd_byte(3) = &HF0
Txd_byte(4) = &HF0
Txd_byte(5) = &HF0
Txd_byte(6) = &HF0
Call Write_register(6)
Txd_byte(1) = Write_reg + En_aa
Txd_byte(2) = &H00
Call Write_register(2)
Txd_byte(1) = Write_reg + En_rxaddr
Txd_byte(2) = &H01
Call Write_register(2)
Txd_byte(1) = Write_reg + Rf_ch
Txd_byte(2) = Frequency_transmitter 'Частота MГц = 2400 + Frequency_transmitter
Call Write_register(2)
Txd_byte(1) = Write_reg + Rf_setup
Txd_byte(2) = &H0F
Call Write_register(2)
Txd_byte(1) = Write_reg + Config_nrf
Txd_byte(2) = &H0E
Call Write_register(2)
'-------------------------------------------------------------------------------
Return
'===============================================================================
'===============================================================================
Передать_данные_nrf24l01:
'-------------------------------------------------------------------------------
Led_txd_nrf24l01 = On_led_nrf24l01
Vcc_nrf24l01 = On_vcc_nrf24l01
Waitms 1
Set Ce_nrf24l01
Waitms 5
Reset Ce_nrf24l01
Reset Csn_nrf24l01
Txd_byte(1) = Flush_tx
Call Write_register(1)
Txd_byte(1) = Write_reg + Status
Txd_byte(2) = &B00110000
Call Write_register(2)
Gosub Setup_tx
Txd_byte(1) = Wr_tx_pload
Txd_byte(2) = Number_transmitter
Txd_byte(3) = Счетчик_измерений_low_byte
Txd_byte(4) = Счетчик_измерений_1_high_byte
Txd_byte(5) = Счетчик_измерений_2_high_byte
Txd_byte(6) = Счетчик_измерений_3_high_byte
Txd_byte(7) = Vcc_txd_nrf24l01_low_byte
Txd_byte(8) = Vcc_txd_nrf24l01_high_byte
Txd_byte(9) = Готов_темп_ds18b20_low_byte
Txd_byte(10) = Готов_темп_ds18b20_high_byte
Txd_byte(11) = Val_timer_min
Txd_byte(12) = Val_timer_sec
Txd_byte(13) = 0
Txd_byte(14) = 0
Txd_byte(15) = 0
Txd_byte(16) = 0
Txd_byte(17) = 0
Txd_byte(18) = 0
Txd_byte(19) = 0
Txd_byte(20) = 0
Txd_byte(21) = 0
Txd_byte(22) = 0
Txd_byte(23) = 0
Txd_byte(24) = 0
Txd_byte(25) = 0
Txd_byte(26) = 0
Txd_byte(27) = 0
Txd_byte(28) = 0
Txd_byte(29) = 0
Txd_byte(30) = 0
Txd_byte(31) = 0
Txd_byte(32) = 0
Txd_byte(33) = 0
'Передаём 33 байта информации, из них 32 байта - наши данные
Call Write_register(33)
Set Ce_nrf24l01
Waitms 1
Reset Ce_nrf24l01
'Выключаем питание Nrf24L01
Vcc_nrf24l01 = Off_vcc_nrf24l01
Led_txd_nrf24l01 = Off_led_nrf24l01
'-------------------------------------------------------------------------------
Return
'===============================================================================
'===============================================================================
Sub Write_register(byval Copy_amount_byte As Byte)
'-------------------------------------------------------------------------------
Reset Csn_nrf24l01
Spiout Txd_byte(1) , Copy_amount_byte
Set Csn_nrf24l01
'-------------------------------------------------------------------------------
End Sub
'===============================================================================
'===============================================================================
' Подпрограмма обработки прерывания TIMER2, происходит 1 или 2 раза в секунду, в зависимости от настроек TIMER2
'===============================================================================
Обработка_прерывания_timer2:
'-------------------------------------------------------------------------------
!push R16
!in R16 , sreg
!push R16
Work_timer_sec:
!lds R16 , {Timer_sec}
!cpi R16 , 0
!brcs Work_timer_min
!breq Work_timer_min
!rjmp Decr_Timer_sec
!rjmp Work_timer_min
Decr_timer_sec:
!subi R16 , 1
!sts {Timer_sec} , R16
!rjmp Exit_прерывания_timer2
Work_timer_min:
!lds R16 , {Timer_min}
!cpi R16 , 0
!brcs Exit_прерывания_timer2
!breq Exit_прерывания_timer2
!rjmp Decr_Timer_min
!rjmp Exit_прерывания_timer2
Decr_timer_min:
!subi R16 , 1
!sts {Timer_min} , R16
!ldi R16 , 59
!sts {Timer_sec} , R16
!rjmp Exit_прерывания_timer2
Work_timer_hour:
!lds R16 , {Timer_hour}
!cpi R16 , 0
!brcs Exit_прерывания_timer2
!breq Exit_прерывания_timer2
!rjmp Decr_Timer_hour
!rjmp Exit_прерывания_timer2
Decr_timer_hour:
!subi R16 , 1
!sts {Timer_hour} , R16
!ldi R16 , 59
!sts {Timer_min} , R16
!rjmp Exit_прерывания_timer2
Exit_прерывания_timer2:
!ldi R16 , 1
!sts {Flag_update_time} , R16
!pop R16
!out sreg , R16
!pop R16
!reti
'-------------------------------------------------------------------------------
Return
'===============================================================================
'===============================================================================
Измерение_avcc:
'-------------------------------------------------------------------------------
Admux = &B_0101_1111 'Готовимся разряжать ёмкость
Waitus 70 'Ждём, пока разрядится ёмкость, рекомендовано Atmel стр.9., п.п.3.4 Band gap measurement (http://www.atmel.com/images/doc8444.pdf)
!ldi R16 , Значение_adcnoise 'Выставляем, как будем спать
!sts SMCR , R16 'Пишем в региср
!sleep 'Отправляемся спать
!nop
!nop
!nop
Admux = &B_0101_1110 'Готовимся измерять Avcc (1.3V(VBG) стр.259 http://www.atmel.com/images/atmel-8159- … asheet.pdf)
Waitus 70 'Время ожидания заряда ёмкости, рекомендовано Atmel стр.9., п.п.3.4 Band gap measurement (http://www.atmel.com/images/doc8444.pdf)
!ldi R16 , Значение_adcnoise 'Выставляем, как будем спать
!sts SMCR , R16 'Пишем в региср
!sleep 'Отправляемся спать
!nop
!nop
!nop
Vcc_txd_nrf24l01_sin = Const_коэффициент_перещета_1_1v / Данные_ацп_avcc_word
Vcc_txd_nrf24l01_word = Vcc_txd_nrf24l01_sin * 100
'-------------------------------------------------------------------------------
Return
'===============================================================================
'===============================================================================
Обработка_прерывания_ацп:
'-------------------------------------------------------------------------------
!push R16
!lds R16 , adcl
!sts {Данные_ацп_avcc_word} , R16
!lds R16 , adch
!sts {Данные_ацп_avcc_word + 1} , R16
!pop R16
!reti
'-------------------------------------------------------------------------------
Return
'===============================================================================
'===============================================================================
Опрос_ds18x20:
'-------------------------------------------------------------------------------
1wreset Port_ds18x20 , Порядковый_номер_ds18x20
1wwrite Const_подготов_чтения_ds18x20 , 1 , Port_ds18x20 , Порядковый_номер_ds18x20
1wwrite Const_чтение_температуры_ds18x20 , 1 , Port_ds18x20 , Порядковый_номер_ds18x20
If Err = 0 Then ' Если работа с шиной прошла без ошибок
Сырые_данные_ds18x20(1) = 1wread(9 , Port_ds18x20 , Порядковый_номер_ds18x20 )
If Сырые_данные_ds18x20(9) = Crc8(сырые_данные_ds18x20(1) , 8) Then ' Если контрольная сумма полученных данных правильная
Gosub Расчет_температуры_ds18x20
Else ' Иначе
' Обработка ошибки CRC полученных данных
End If ' If Ответ_датчика_ds18x20(9) = Crc8(ответ_датчика_ds18x20(1) , 8) Then ' Проверяем контрольную сумму полученных данных
Готов_темпер_ds18b20_sin = Температура_single * 10
Готов_темпер_ds18b20_int = Готов_темпер_ds18b20_sin
Else ' Иначе
' Обработка ошибки работы с шиной 1wire
End If ' If Err = 0 Then
Выход_опрос_ds18x20:
' Gosub Запуск_измерения_ds18x20
'-------------------------------------------------------------------------------
Return
'===============================================================================
'===============================================================================
Расчет_температуры_ds18x20:
'-------------------------------------------------------------------------------
Температура_single = Температура_integer
Shift Температура_single , Right , 4 , Signed
'-------------------------------------------------------------------------------
Return
'===============================================================================
'===============================================================================
Запуск_измерения_ds18x20:
'-------------------------------------------------------------------------------
1wreset Port_ds18x20 , Порядковый_номер_ds18x20
1wwrite Const_подготов_чтения_ds18x20 , 1 , Port_ds18x20 , Порядковый_номер_ds18x20
1wwrite Const_запуск_измерения_ds18x20 , 1 , Port_ds18x20 , Порядковый_номер_ds18x20
'-------------------------------------------------------------------------------
Return
'===============================================================================