Среднечастотный частотомер на AVR. Часть 1, динамическая индикация.

Собственно к схеме генератора претензий нет, некоторые вещи я бы сделал по другому, но это потом в процессе изготовления. Мне сразу не понравилась цифровая шкала генератора (там же, страница 2). Его программа представляет сборку из скетчей Arduino, я их не понимаю и не горю желанием изучать. Да и применение ATmega328 мне показалось неоправданно жирным. Короче решил спроектировать свою цифровую шкалу на ATmega8A. Результат представляю вашему вниманию, код написан на ассемблере AVR в среде AVR Studio 4.19.
Принцип электронно-счетного способа измерения частоты заключается в непосредственном подсчете кол-ва импульсов измеряемой частоты за образцовый период времени. Частота и время являются обратными величинами и связаны формулой F = 1 / T, где частота представлена в герцах, а время в секундах.
В данном измерителе образцовый период времени равен 1 сек, кол-во подсчитаных за этот период импульсов будет равно измеряемой частоте в герцах.
Формирователем образцового периода является Таймер 2, работающий в асинхронном режиме от «часового» кварца 32768 Hz. Контроллер тактируется от внутреннего RC-генератора частотой 8 MHz. Максимальная частота измеряемых импульсов при этом равна 8 / 2,5 = 3,2 MHz.
По классификации DIHALT программа представляет собой «Флаговый автомат + прерывания».
Я буду приводить куски программы с описанием для лучшего понимания работы. Полные исходники можно скачать в конце статьи. К исходникам приложен проект Proteus 7.10 с симуляцией работы программы. Статья описывает особенности примененных кодовых решений, схемотехническое построение и схему подключения можно посмотреть на схеме Proteus. Сразу скажу, на схеме Proteus могут отсутствовать некоторые детали, не нужные для симуляции, но обязательные при изготовлении конструкции. Но ориентироваться на нее можно, тем более статья не расчитана на новичков в схемотехнике AVR, больше на программистов.
Проект включает файл макросов FQMacros.inc. Применение макросов для RISC контроллеров делает текст проекта короче и более удобочитаемым. Содержание:
;------ MACROS -----------------------------------------------------------------;
; OUTI @0 (константа)
.MACRO OUTI ; вывод константы в порт
LDI Temp, @1 ;
OUT @0, Temp ;
.ENDM
;
; LDIL @0 (регистр (R0..R15)), @1 (константа)
.MACRO LDIL ; загрузка константы в младший регистр
LDI Temp, @1 ;
MOV @0, Temp ;
.ENDM
;
; LDIZ @0 (адрес памяти программ (слово))
.MACRO LDIZ ; загрузка адреса перед LPM
LDI ZL, Low(@0*2) ;
LDI ZH, High(@0*2) ;
.ENDM
;
; LDIDX @0 (индексный регистр X, Y, Z), @1 (адрес (слово))
.MACRO LDIDX ; загрузка адреса в индексный регистр
LDI @0L, Low(@1) ;
LDI @0H, High(@1) ;
.ENDM
;
; ADIDX @0 (индексный регистр X, Y, Z), @1 (регистр)
.MACRO ADIDX ; сложение адреса со смещением
ADD @0L, @1 ;
LDI Temp, 0x00 ;
ADC @0H, Temp ;
.ENDM
Из названия классификации понятно, что логика работы флагового автомата построена на работе с флагами. Под флагом понимается логический примитив, который может принимать два состояния — выключен/включен. В двоичной логике это бит.
И хотя в AVR нет полноценного битового процессора (как в MCS-51), построить флаговый автомат не так сложно. Принцип один и тот же, различается реализация.
;------ Предназначение регистров -----------------------------------------------;
.DEF Counter = R0 ; Счетчик динамической индикации
.DEF FxOVF = R1 ; Старший байт частоты (счетный)
.DEF Safe = R16 ; Сохранение SREG в прерывании
.DEF Temp = R17 ; Временный регистр
.DEF Cycler = R18 ; Временный регистр
.DEF BITx1 = R19 ; Битовый регистр
.EQU MRK_BCD = 0 ; Флаг преобразования PackBCD <- BIN
.EQU MRK_B2B = 1 ; Флаг преобразования UnpackBCD <- PackBCD
.EQU MRK_Symb = 2 ; Флаг преобразования Symbols code <- UnpackBCD
.EQU MRK_Key = 6 ; Флаг опроса клавиатуры
.EQU MRK_Dyn = 7 ; Флaг обновления динамической индикации
Битовый регистр BITx1 назначен из «верхних» регистров как работающий со всеми командами AVR. Тут же предопределены и флаги.
Задействованы прерывания всех трех имеющихся таймеров ATMega8A:
- Таймер 0, восьмиразрядный, выполняет функцию системного таймера для управления динамической индикацией. При частоте контроллера 8 МГц и предделителе 64 частота прерываний ~488 Гц (флаг MRK_Dyn), что дает обновление с частотой ~61 Гц для каждого разряда (при задействованных 8 разрядах). Если задействованы 7 разрядов, каждый разряд будет обновляться с частотой ~70 Гц и т.д.
- Таймер 1, шестнадцатиразрядный, выполняет функцию счета импульсов с внешнего входа. Т.к. шестнадцатиразрядный счетчик может вместить не более 65536 импульсов, он программно расширен еще на 8 разрядов (FxOVF, в сумме 24 разряда), что дает емкость 16777216 импульсов. В данном случае это более чем достаточно, т.к. частота на входе таймера ограничена 2,5 тактовой (3,2 МГц), что дает 3200000 импульсов. Таким образом подсчет импульсов измеряемой частоты производится аппаратно шестнадцатиразрядным таймером, при переполнении его прерывание инкрементирует дополнительный регистр.
- Таймер 2, восьмиразрядный, выполняет функцию формирования измерительного интервала. Для этого к нему подключен «часовой» кварц 32768 Гц, что при предделителе 128 позволяет получить импульсы с частотой 1 Гц. Прерывание переносит результат измерений из рабочих регистров в ОЗУ, обнуляет рабочие счетные регистры, устанавливает флаг готовности результата измерений (MRK_BCD) и перед новым измерением обнуляет свой регистр и предделитель. Начинается новое измерение, предыдущее обрабатывается флаговым автоматом.
- Регенерация динамической индикации по прерыванию таймера 0 (~488 Гц).
- Инкремент старшего байта счетного регистра по прерыванию таймера 1 (~49 Гц при входной частоте 3,2 МГц).
- Перенос содержимого счетного регистра в ОЗУ и обработка входных данных по прерыванию таймера 2 (1 Гц).
;------ Таблица прерываний------------------------------------------------------;
.CSEG
;------ Начальная инициализация ------------------------------------------------;
.ORG 0 ; 0x0000
RJMP _Reset ; Power-on Reset
;------ Прерывание таймера 2 ---------------------------------------------------;
.ORG OVF2addr ; 0x0004 (в словах)
RJMP OVF2_VECTOR ; Timer/Counter2 Overflow
;------ Прерывание таймера 1 ---------------------------------------------------;
.ORG OVF1addr ; 0x0008 (в словах)
RJMP OVF1_VECTOR ; Timer/Counter1 Overflow
;------ Прерывание таймера 0 ---------------------------------------------------;
.ORG OVF0addr ; 0x0009 (в словах)
IN Safe, SREG ; сохранить флаги SREG (SBR изменяет флаги Z,C,N,V,H,S)
SBR BITx1, (1<<MRK_Dyn) ; установить флаг начала регенерации дисплея
OUT SREG, Safe ; восстановить флаги SREG
RETI ;
.ORG INT_VECTORS_SIZE ; 0x0013 (в словах)
Как обычно по нулевому адресу расположен переход на код инициализации внутренних используемых устройств контроллера, предустановка переменных и т.д. Здесь можно отметить не совсем привычный код инициализации таймера 2 в асинхронном режиме. После включения асинхронного режима (бит AS2 регистра ASSR) и установки режима таймера (регистр TCCR2) разрешать общие прерывания можно только после подтверждения таймером о изменении режима. В зависимости от того, какой регистр был изменен TCNT2, OCR2, или TCCR2 подтверждение будет выдано битами TCN2UB, OCR2UB, или TCR2UB регистра ASSR. Пока хоть один бит единичный, включать прерывания нельзя.
;------ внешние подключения ----------------------------------------------------;
.EQU T1 = PORTD5 ; вход частотомера, ножка 11 PDIP
;------ подключение разрядов семисегментного индикатора ------------------------;
.EQU Rat1 = PORTB0 ; разряд PORTB0, PORTB, ножка 14 PDIP
.EQU Rat2 = PORTD7 ; разряд PORTD7, PORTD, ножка 13 PDIP
.EQU Rat3 = PORTD6 ; разряд PORTD6, PORTD, ножка 12 PDIP
.EQU Rat4 = PORTD4 ; разряд PORTD4, PORTD, ножка 6 PDIP
.EQU Rat5 = PORTD3 ; разряд PORTD3, PORTD, ножка 5 PDIP
.EQU Rat6 = PORTD2 ; разряд PORTD2, PORTD, ножка 4 PDIP
.EQU Rat7 = PORTD1 ; разряд PORTD1, PORTD, ножка 3 PDIP
.EQU Rat8 = PORTD0 ; разряд PORTD0, PORTD, ножка 2 PDIP
;------ подключение сегментов семисегментного индикатора -----------------------;
.EQU SegA = PORTC5 ; разряд PORTC5, PORTC, ножка 28 PDIP
.EQU SegB = PORTC4 ; разряд PORTC4, PORTC, ножка 27 PDIP
.EQU SegC = PORTC3 ; разряд PORTC3, PORTC, ножка 26 PDIP
.EQU SegD = PORTC2 ; разряд PORTC2, PORTC, ножка 25 PDIP
.EQU SegE = PORTC1 ; разряд PORTC1, PORTC, ножка 24 PDIP
.EQU SegF = PORTC0 ; разряд PORTC0, PORTC, ножка 23 PDIP
.EQU SegG = PORTB2 ; разряд PORTB1, PORTB, ножка 16 PDIP
.EQU SegH = PORTB1 ; разряд PORTB2, PORTB, ножка 15 PDIP
;
_Reset: ; Начальная инициализация
;------ Установить вершину стека -----------------------------------------------;
OUTI SPH, High(RAMEND) ;
OUTI SPL, Low(RAMEND) ;
;------ Отключить сторожевой таймер --------------------------------------------;
OUTI WDTCR, (1<<WDE)|(1<<WDCE) ;
OUTI WDTCR, (0<<WDE) ;
;------ Отключить аналоговый компаратор ----------------------------------------;
OUTI ACSR, (1<<ACD) ;
;------ Конфигурация портов ----------------------------------------------------;
OUTI DDRB, (1<<SegG)|(1<<SegH)|(1<<Rat1)
OUTI DDRC, (1<<SegA)|(1<<SegB)|(1<<SegC)|(1<<SegD)|(1<<SegE)|(1<<SegF)
OUTI DDRD, (1<<Rat8)|(1<<Rat7)|(1<<Rat6)|(1<<Rat5)|(1<<Rat4)|(1<<Rat3)|(1<<Rat2)
OUTI PORTD, (1<<T1) ; Т1 - вход с поддтяжкой
;------ Очистка регистров ------------------------------------------------------;
CLR FxOVF ; обнуление счетного регистра
CLR BITx1 ; обнуление битового регистра
CLR Counter ; обнуление счетчика динамической индикации
CLRIBIT PORTD, Rat8 ; гашение
CLRIBIT PORTD, Rat7 ; всех
CLRIBIT PORTD, Rat6 ; разрядов
CLRIBIT PORTD, Rat5 ; индикатора
CLRIBIT PORTD, Rat4 ; -//-
CLRIBIT PORTD, Rat3 ; -//-
CLRIBIT PORTD, Rat2 ; -//-
CLRIBIT PORTB, Rat1 ; -//-
;------ Настроить таймер 0, режим Normal ---------------------------------------;
OUTI TCCR0, (1<<CS01)|(1<<CS00); прескалер 64
;------ Настроить таймер 1, режим Normal, внешний импульс ----------------------;
OUTI TCCR1B, (1<<CS12)|(1<<CS11)|(1<<CS10)
;------ Настроить таймер 2, Asynchronous Operation -----------------------------;
; на входах TOSC1 (XTAL1) и TOCSC2 (XTAL2) "часовой" кварц 32768 Hz
OUTI ASSR, (1<<AS2)
; Normal, прерывание по переполнению
OUTI TCCR2, (1<<CS22)|(1<<CS20); прескалер 128
;------ Включить прерывания ----------------------------------------------------;
OUTI TIMSK, (1<<TOIE0)|(1<<TOIE1)|(1<<TOIE2) ; разрешить прерывания таймеров
SEI_TEST_EN: ; проверка на допустимость разрешения прерываний
IN Temp, ASSR ;
ANDI Temp, (1<<TCN2UB)|(1<<OCR2UB)|(1<<TCR2UB)
TST Temp ; проверка битов TCN2UB, OCR2UB, TCR2UB
BRNE SEI_TEST_EN ; возврат, если биты не сброшены
SEI ; разрешить прерывания
;------ Номер версии прошивки --------------------------------------------------;
LDIDX Z, Ident*2+iSize-vSize-1 ; Загрузить адрес в идентификаторе
LDIDX Y, RAM_Symbol+vSize ; Загрузить адрес в буфере кодов цифр
LDI Cycler, vSize ; длина строки версии
locIdent:
LPM Temp, Z+ ; Загрузить байт строки версии
ST -Y, Temp ; перенести в буфер кодов цифр
DEC Cycler ;
BRNE locIdent ;
О макросе CLRIBIT и идентификаторе Ident см. ниже.
Прерывания первой и второй ветви могут вносить погрешность в измерения за счет задержки счетного прерывания (AVR не имеет регистра приоритетности прерываний). Для мимизации такой погрешности, подпрограммы обработки сделаны максимально короткими. Подпрограмма таймера 0 собственно и не оформлена в виде подпрограммы, ее код размещен прямо в таблице прерываний на месте прерываний USART. Разместить таким же образом подпрограмму таймера 1 не хватает места.
Сокращению времени обработки служит и использование специально выделенного регистра Safe, работа с ним в два раза быстрее использования стека (POP, PUSH). Сохранение и восстановление SREG обязательно, т.к. команда SBR может изменить флаги Z,C,N,V,H,S.
;------ Прерывание таймера 1 ---------------------------------------------------;
OVF1_VECTOR: ; INC изменяет флаги Z,N,V,S
IN Safe, SREG ; сохранить флаги SREG
INC FxOVF ; инкрементировать счетный регистр
OUT SREG, Safe ; восстановить флаги SREG
RETI ;
;------ Прерывание таймера 2 (раз в 1 сек) -------------------------------------;
OVF2_VECTOR: ; SBR изменяет флаги Z,C,N,V,H,S; CLR - Z,C,N,V,S
MOV Safe, Temp ; сохранить временный регистр
STS RAM_Val_H, FxOVF ; перенос значения счетного регистра в память
IN Temp, TCNT1L ; перенос значения
STS RAM_Val_L, Temp ; счетного
IN Temp, TCNT1H ; регистра
STS RAM_Val_M, Temp ; в память
LDI Temp, 0x00 ; обнуление
OUT TCNT1H, Temp ; счетного
OUT TCNT1L, Temp ; регистра
OUTI SFIOR, (1<<PSR2) ; сброс предделителя таймера 2
MOV Temp, Safe ; восстановить временный регистр
IN Safe, SREG ; сохранить флаги SREG
CLR FxOVF ; обнуление счетного регистра
SBR BITx1, (1<<MRK_BCD) ; установить флаг начала обработки измерений
OUT SREG, Safe ; восстановить флаги SREG
RETI ;
Распределение оперативной памяти:
;------ Разрядность дисплея ----------------------------------------------------;
.EQU BufSize = 7 ; Кол-во цифр на диcплее
.;----- Резервирование ячеек ОЗУ -----------------------------------------------;
.DSEG
.ORG SRAM_START
RAM_Val_L: .byte 1 ; Измеренное значение, младший байт
RAM_Val_M: .byte 1 ; Измеренное значение, средний байт
RAM_Val_H: .byte 1 ; Измеренное значение, старший байт
BegPackBCD:
RAM_BCD_0: .byte 1 ; Упакованный BCD, 1 байт
RAM_BCD_1: .byte 1 ; Упакованный BCD, 2 байт
RAM_BCD_2: .byte 1 ; Упакованный BCD, 3 байт
RAM_BCD_3: .byte 1 ; Упакованный BCD, 4 байт
EndPackBCD:
.EQU SizePackBCD = EndPackBCD - BegPackBCD
RAM_UnBCD: .byte BufSize ; Неупакованные BCD
RAM_Symbol: .byte BufSize ; Коды цифр (symbols)
Цикл обработки результата измерения при этом выглядит так:
- Прерывание таймера 2 (OVF2_VECTOR) переносит измеренное значение в ОЗУ (RAM_Val_X);
- Подпрограмма PackBCD < — BIN преобразует бинарное значение в упакованный BCD (RAM_BCD_X);
- Подпрограмма UnpackBCD < — PackBCD распаковывает BCD в неупакованный (RAM_UnBCD);
- Подпрограмма Symbols code < — UnpackBCD преобразует неупакованный BCD в коды символов семисегментного дисплея (RAM_Symbol);
- Цикл может в любое время прерываться регенерацией дисплея и инкрементом счетного регистра;
Main: ; Основной цикл
;
;== Преобразование Symbols code <- UnpackBCD с гашением 0, MRK_Symb = 1 ========;
SBRS BITx1, MRK_Symb ; если нет флага начала обработки, на выход
RJMP locMP_02 ;
// Код подпрограммы UnpackBCDtoSymbolsCode
CBR BITx1, (1<<MRK_Symb) ; сбросить флаг текущего шага
locMP_02: ;=====================================================================;
;
;== Преобразование UnpackBCD <- PackBCD, MRK_B2B = 1 ===========================;
SBRS BITx1, MRK_B2B ; если нет флага начала обработки, на выход
RJMP locMP_01 ;
// Код подпрограммы PackBCDtoUnpackBCD
SBR BITx1, (1<<MRK_Symb) ; установить флаг следующего шага
CBR BITx1, (1<<MRK_B2B) ; сбросить флаг текущего шага
locMP_01: ;=====================================================================;
;
;== Преобразование PackBCD <- BIN, MRK_BCD = 1 =================================;
SBRS BITx1, MRK_BCD ; если нет флага начала обработки, на выход
RJMP locMP_00 ;
// Код подпрограммы BINtoPackBCD
SBR BITx1, (1<<MRK_B2B) ; установить флаг следующего шага
CBR BITx1, (1<<MRK_BCD) ; сбросить флаг текущего шага
locMP_00: ;=====================================================================;
;
;== Регенерация дисплея, MRK_Dyn = 1 ===========================================;
SBRS BITx1, MRK_Dyn ; если нет флага обновления, на выход
RJMP locMP_Dn ;
;*******************************************************************************;
; 1. Гасится текущий отображаемый разряд; ;
;*******************************************************************************;
; 2. Счетчик разрядов декрементируется; ;
; . . . . . . . . . . . . . .
; После цикла сканирования во время перезагрузки счетчика
SBR BITx1, (1<<MRK_Key) ; установить флаг опроса клавиатуры
; . . . . . . . . . . . . . .
;*******************************************************************************;
; 3. Устанавливается семисегментный код символа; ;
;*******************************************************************************;
; 4. Зажигается следующий разряд; ;
;*******************************************************************************;
CBR BITx1, (1<<MRK_Dyn) ; сбросить флаг обновления индикации
locMP_Dn: ;=====================================================================;
;
;== Опрос клавиатуры, MRK_Key = 1 ==============================================;
SBRS BITx1, MRK_Key ; если нет флага начала обработки, на выход
RJMP locMP_Kb ;
// Обработка кнопок, не реализовано
CBR BITx1, (1<<MRK_Key) ; сбросить флаг
locMP_Kb:
;
RJMP Main ; бесконечный цикл
Обратите внимание, что подпрограммы обработки результата измерений размещены в обратной последовательности. Это нужно для того, чтобы после каждого действия происходил выход в главный цикл для проверки флагов регенерации дисплея и опроса клавиатуры.
Код первой подпрограммы обрабатывающей результаты измерения BINtoPackBCD основан на аппноте Atmel AVR204 и преобразует трехбайтовое бинарное представление числа в четырехбайтовый упакованный BCD формат. Название подпрограмм даны условно, т.к. во флаговом автомате они оформлены нестандартно, без метки. Полный код BINtoPackBCD:
.DEF tBCD0 = R2 ; BCD value digits 1 and 0
.DEF tBCD1 = R3 ; BCD value digits 3 and 2
.DEF tBCD2 = R4 ; BCD value digits 4 and 5
.DEF tBCD3 = R5 ; BCD value digits 6 and 7
.EQU AdBCD0 = 2 ; address of tBCD0
.EQU AdBCD3 = 5 ; address of tBCD3
.DEF FxBUF_L = R20 ; Младший байт частоты (рабочий)
.DEF FxBUF_M = R21 ; Средний байт частоты (рабочий)
.DEF FxBUF_H = R22 ; Старший байт частоты (рабочий)
;
;== Преобразование PackBCD <- BIN, MRK_BCD = 1 =================================;
SBRS BITx1, MRK_BCD ; если нет флага начала обработки, на выход
RJMP locMP_00 ;
//
IN Temp, MCUCSR ; проверка на холодный старт
ANDI Temp, (1<<EXTRF)|(1<<PORF);
BREQ locBCD0 ; если нет - выход
CLR Temp ;
OUT MCUCSR, Temp ;
RJMP locBCD4 ; отбрасывание первого измерения
locBCD0:
LDS FxBUF_H, RAM_Val_H ; загрузка
LDS FxBUF_M, RAM_Val_M ; измеренного
LDS FxBUF_L, RAM_Val_L ; значения из ОЗУ
;--- Код на основе аппноты AVR204 ----------------------------------------------;
LDI Cycler, 24 ; Кол-во итераций (24 бита)
CLR tBCD3 ; очистить
CLR tBCD2 ; регистры
CLR tBCD1 ; результата
CLR tBCD0 ; -//-
CLR ZH ; очистить старший байт индексного регистра
locBCD1:
LSL FxBUF_L ; сдвинуть
ROL FxBUF_M ; входное
ROL FxBUF_H ; значение
ROL tBCD0 ; и вдвинуть
ROL tBCD1 ; его
ROL tBCD2 ; в
ROL tBCD3 ; результат
DEC Cycler ; декрементировать счетчик цикла
BREQ locBCD3 ; выход при нуле
LDI r30, AdBCD3+1 ; в Z адрес старшего регистра результата + 1
locBCD2:
LD Temp, -Z ; загрузить старший регистр результата (предекремент)
SUBI Temp, -$03 ; сложить с 0x03
SBRC Temp, 3 ; если бит 3 очищен, пропустить след. команду
ST Z, Temp ; сохранить в регистре результата
LD Temp, Z ; загрузить старший регистр результата
SUBI Temp, -$30 ; сложить с 0x30
SBRC Temp, 7 ; если бит 7 очищен, пропустить след. команду
ST Z, Temp ; сохранить в регистре результата
CPI ZL, AdBCD0 ; конец достигнут?
BRNE locBCD2 ; если нет, повторить
RJMP locBCD1 ; продолжить цикл
locBCD3:
STS RAM_BCD_0, tBCD0 ; сохранение
STS RAM_BCD_1, tBCD1 ; упакованного
STS RAM_BCD_2, tBCD2 ; BCD
STS RAM_BCD_3, tBCD3 ; в ОЗУ
//
SBR BITx1, (1<<MRK_B2B) ; установить флаг следующего шага
locBCD4:
CBR BITx1, (1<<MRK_BCD) ; сбросить флаг текущего шага
locMP_00: ;=====================================================================;
;
.UNDEF tBCD0 ; R2
.UNDEF tBCD1 ; R3
.UNDEF tBCD2 ; R4
.UNDEF tBCD3 ; R5
.UNDEF FxBUF_L ; R20
.UNDEF FxBUF_M ; R21
.UNDEF FxBUF_H ; R22
Обратите внимание, в коде проверяется наличие как флага «холодного» старта PORF, так и флага внешнего сброса EXTRF. Это связано с тем, что в модели Proteus вместо PORF устанавливается EXTRF. Пришлось извернуться, для железа это безразлично, реакция на «холодный» и «теплый» старт будет одинакова.
В AVR очень неудобно работать с упакованными BCD числами, поэтому следующей подпрограммой PackBCDtoUnpackBCD мы их распакуем:
.DEF Mask_4 = R20 ; маска ниббла
.DEF PackBCD = R21 ; упакованный BCD
.DEF CopyBCD = R22 ; копия -//-
;
;== Преобразование UnpackBCD <- PackBCD, MRK_B2B = 1 ===========================;
SBRS BITx1, MRK_B2B ; если нет флага начала обработки, на выход
RJMP locMP_01 ;
//
LDIDX X, RAM_UnBCD ; адрес буфера неупакованного BCD
LDIDX Y, RAM_BCD_0 ; адрес буфера упакованного BCD
LDI Mask_4, 0b00001111 ; маска ниббла
LDI Cycler, SizePackBCD ; кол-во байт упакованного BCD
locP2U:
LD PackBCD, Y+ ; чтение упакованного BCD
MOV CopyBCD, PackBCD ; копия
AND PackBCD, Mask_4 ; младший ниббл
ST X+, PackBCD ; в буфер неупакованного BCD
SWAP CopyBCD ; перевернем копию
AND CopyBCD, Mask_4 ; старший ниббл
ST X+, CopyBCD ; в буфер неупакованного BCD
DEC Cycler ;
BRNE locP2U ;
//
SBR BITx1, (1<<MRK_Symb) ; установить флаг следующего шага
CBR BITx1, (1<<MRK_B2B) ; сбросить флаг текущего шага
locMP_01: ;=====================================================================;
;
.UNDEF Mask_4 ; R20
.UNDEF PackBCD ; R21
.UNDEF CopyBCD ; R22
Чтобы полностью подготовить результат к выводу на семисегментные индикаторы, необходим программный дешифратор BCD кода в семисегментный. Заодно можно погасить незначащие нули.
;== Преобразование Symbols code <- UnpackBCD с гашением 0, MRK_Symb = 1 ========;
SBRS BITx1, MRK_Symb ; если нет флага начала обработки, на выход
RJMP locMP_02 ;
//
CLT ; очистить флаг Т
LDIDX X, RAM_UnBCD+BufSize ; конец буфера неупакованного BCD
LDIDX Y, RAM_Symbol+BufSize ; конец буфера кодов цифр
LDI Cycler, BufSize ; кол-во знакомест
locSm0:
DEC Cycler ; флаг Z=1 - последняя цифра
LDIZ TBL_DIGITS ; Загрузить адрес таблицы кодов символов
LD Temp, -X ; загрузить неупакованный BCD
BRTS locSm1 ; если Т установлен
BREQ locSm1 ; если последняя цифра
TST Temp ;
BREQ locSm2 ; если ноль
SET ; установить флаг Т
locSm1:
ADD ZL, Temp ; Найти
CLR Temp ; нужный
ADC ZH, Temp ; символ
LPM Temp, Z ; загрузить код символа
locSm2:
ST -Y, Temp ; сохранить код символа
TST Cycler ;
BRNE locSm0 ;
//
CBR BITx1, (1<<MRK_Symb) ; сбросить флаг текущего шага
locMP_02: ;=====================================================================;
Код перебирает все цифры из буфера неупакованных BCD начиная со старшей. Пока в буфере 0 он будет перенесен в буфер кодов цифр без преобразования, а т.к. все биты равны нулю, для семисегментного индикатора это гашение. Как только встретился не ноль, будет установлен флаг Т. После этого текущий и все последующие разряды будут пребразованы в коды семисегментного индикатора. Последняя (самая младшая) цифра в числе всегда переносится в буфер кодов цифр с преобразованием (это если на индикаторе одни нули).
В представленной программе особенностью управления сегментами и разрядами индикатора является их индивидуальное управление. Сегментам и разрядам можно назначить выводы любых портов в произвольном порядке. Это упрощает разводку печатной платы. Например у данного варианта программы для корпуса PDIP выводы разрядов индикатора с одной стороны корпуса, сегментов с другой.
;*******************************************************************************;
; 1. Гасится текущий отображаемый разряд; ;
;*******************************************************************************;
MOV TmpDyn, Counter ;
ANDI TmpDyn, 0b00000111 ; не более 8 разрядов
LSL TmpDyn ; Команда занимает 2 слова
LDIDX Z, LocEn0 ; адрес таблицы команд
ADIDX Z, TmpDyn ; адрес команды в таблице
IJMP ; переход на команду
LocEn0:
;--- Разряд 1 ------------------------------------------------------------------;
CLRIBIT PORTB, Rat1 ;
RJMP LocEn1 ;
;--- Разряд 2 ------------------------------------------------------------------;
CLRIBIT PORTD, Rat2 ;
RJMP LocEn1 ;
;--- Разряд 3 ------------------------------------------------------------------;
CLRIBIT PORTD, Rat3 ;
RJMP LocEn1 ;
;--- Разряд 4 ------------------------------------------------------------------;
CLRIBIT PORTD, Rat4 ;
RJMP LocEn1 ;
;--- Разряд 5 ------------------------------------------------------------------;
CLRIBIT PORTD, Rat5 ;
RJMP LocEn1 ;
;--- Разряд 6 ------------------------------------------------------------------;
CLRIBIT PORTD, Rat6 ;
RJMP LocEn1 ;
;--- Разряд 7 ------------------------------------------------------------------;
CLRIBIT PORTD, Rat7 ;
RJMP LocEn1 ;
;--- Разряд 8 ------------------------------------------------------------------;
CLRIBIT PORTD, Rat8 ;
LocEn1:
;*******************************************************************************;
; 2. Счетчик разрядов декрементируется; ;
;*******************************************************************************;
MOV TmpDyn, Counter ;
DEC TmpDyn ; счетчик разрядов декрементируется
BRPL LocDn0 ; обработаны еще не все разряды
LDI TmpDyn, BufSize-1 ; предустановка счетчика
SBR BITx1, (1<<MRK_Key) ; установить флаг опроса клавиатуры
LocDn0:
MOV Counter, TmpDyn ; сохраним до следующей регенерации
;*******************************************************************************;
; 3. Устанавливается семисегментный код символа; ;
;*******************************************************************************;
LDIDX Z, RAM_Symbol ; адрес буфера кодов цифр
ADIDX Z, TmpDyn ; Найти нужный символ
LD Pattern, Z ; Загрузить код цифры
;--- 1 сегмент -----------------------------------------------------------------;
LSL Pattern ; сдвиг влево, старший разряд в С
BRCS loc70 ; если С = 1
CLRIBIT PortB, SegH ;
loc70:
BRCC loc71 ; если С = 0
SETIBIT PortB, SegH ;
loc71:
;--- 2 сегмент -----------------------------------------------------------------;
LSL Pattern ; сдвиг влево, следующий разряд в С
BRCS loc60 ; если С = 1
CLRIBIT PortB, SegG ;
loc60:
BRCC loc61 ; если С = 0
SETIBIT PortB, SegG ;
loc61:
;--- 3 сегмент -----------------------------------------------------------------;
LSL Pattern ; сдвиг влево, следующий разряд в С
BRCS loc50 ; если С = 1
CLRIBIT PortC, SegF ;
loc50:
BRCC loc51 ; если С = 0
SETIBIT PortC, SegF ;
loc51:
;--- 4 сегмент -----------------------------------------------------------------;
LSL Pattern ; сдвиг влево, следующий разряд в С
BRCS loc40 ; если С = 1
CLRIBIT PortC, SegE ;
loc40:
BRCC loc41 ; если С = 0
SETIBIT PortC, SegE ;
loc41:
;--- 5 сегмент -----------------------------------------------------------------;
LSL Pattern ; сдвиг влево, следующий разряд в С
BRCS loc30 ; если С = 1
CLRIBIT PortC, SegD ;
loc30:
BRCC loc31 ; если С = 0
SETIBIT PortC, SegD ;
loc31:
;--- 6 сегмент -----------------------------------------------------------------;
LSL Pattern ; сдвиг влево, следующий разряд в С
BRCS loc20 ; если С = 1
CLRIBIT PortC, SegC ;
loc20:
BRCC loc21 ; если С = 0
SETIBIT PortC, SegC ;
loc21:
;--- 7 сегмент -----------------------------------------------------------------;
LSL Pattern ; сдвиг влево, следующий разряд в С
BRCS loc10 ; если С = 1
CLRIBIT PortC, SegB ;
loc10:
BRCC loc11 ; если С = 0
SETIBIT PortC, SegB ;
loc11:
;--- 8 сегмент -----------------------------------------------------------------;
LSL Pattern ; сдвиг влево, следующий разряд в С
BRCS loc00 ; если С = 1
CLRIBIT PortC, SegA ;
loc00:
BRCC loc01 ; если С = 0
SETIBIT PortC, SegA ;
loc01:
;*******************************************************************************;
; 4. Зажигается следующий разряд; ;
;*******************************************************************************;
MOV TmpDyn, Counter ;
ANDI TmpDyn, 0b00000111 ; не более 8 разрядов
LSL TmpDyn ; Команда занимает 2 слова
LDIDX Z, (LocDs0) ; адрес таблицы команд
ADIDX Z, TmpDyn ; адрес команды в таблице
IJMP ; переход на команду
LocDs0:
;--- Разряд 1 ------------------------------------------------------------------;
SETIBIT PORTB, Rat1 ;
RJMP LocDs1 ;
;--- Разряд 2 ------------------------------------------------------------------;
SETIBIT PORTD, Rat2 ;
RJMP LocDs1 ;
;--- Разряд 3 ------------------------------------------------------------------;
SETIBIT PORTD, Rat3 ;
RJMP LocDs1 ;
;--- Разряд 4 ------------------------------------------------------------------;
SETIBIT PORTD, Rat4 ;
RJMP LocDs1 ;
;--- Разряд 5 ------------------------------------------------------------------;
SETIBIT PORTD, Rat5 ;
RJMP LocDs1 ;
;--- Разряд 6 ------------------------------------------------------------------;
SETIBIT PORTD, Rat6 ;
RJMP LocDs1 ;
;--- Разряд 7 ------------------------------------------------------------------;
SETIBIT PORTD, Rat7 ;
RJMP LocDs1 ;
;--- Разряд 8 ------------------------------------------------------------------;
SETIBIT PORTD, Rat8 ;
LocDs1:
Программа может управлять индикаторами и с общим анодом и с общим катодом. Достигнуто это с помощью средств условной компиляции препроцессора ассемблера. В программе определен дефайн и два макроса, в случае компиляции для индикатора с ОА дефайн нужно раскоментировать:
;#define Common_Anode_Display ; дисплей с ОА, инверсное управление
;
.MACRO SETIBIT ; установка бита в порту
#ifdef Common_Anode_Display
CBI @0, @1 ; инверсная
#else
SBI @0, @1 ; прямая
#endif
.ENDM
;
.MACRO CLRIBIT ; сброс бита в порту
#ifdef Common_Anode_Display
SBI @0, @1 ; инверсный
#else
CBI @0, @1 ; прямой
#endif
.ENDM
Чаще всего сегменты индикатора подключают к портам контроллера руководствуясь удобством разводки печатной платы. Для отображения семисегментного разряда с десятичной точкой достаточно байта. Каждый сегмент и точка будут соответствовать своему биту.
Для удобства подбора сегментов и соответствующих им битов в программе применен следующий способ определения кодов символов.
;==== Битовые маски для дисплея ================================================;
;
; a
; --
; f| |b
; g--
; e| |c
; -- .h
; d
;
.EQU Seg_A = 0b00000001
.EQU Seg_B = 0b00000010
.EQU Seg_C = 0b00000100
.EQU Seg_D = 0b00001000
.EQU Seg_E = 0b00010000
.EQU Seg_F = 0b00100000
.EQU Seg_G = 0b01000000
.EQU Seg_H = 0b10000000
;
.EQU CH_0 = Seg_A | Seg_B | Seg_C | Seg_D | Seg_E | Seg_F
.EQU CH_1 = Seg_B | Seg_C
.EQU CH_2 = Seg_A | Seg_B | Seg_D | Seg_E | Seg_G
.EQU CH_3 = Seg_A | Seg_B | Seg_C | Seg_D | Seg_G
.EQU CH_4 = Seg_B | Seg_C | Seg_F | Seg_G
.EQU CH_5 = Seg_A | Seg_C | Seg_D | Seg_F | Seg_G
.EQU CH_6 = Seg_A | Seg_C | Seg_D | Seg_E | Seg_F | Seg_G
.EQU CH_7 = Seg_A | Seg_B | Seg_C
.EQU CH_8 = Seg_A | Seg_B | Seg_C | Seg_D | Seg_E | Seg_F | Seg_G
.EQU CH_9 = Seg_A | Seg_B | Seg_C | Seg_D | Seg_F | Seg_G
;
.EQU CH_v = Seg_C | Seg_D | Seg_E
;
TBL_DIGITS:
.DB CH_0, CH_1, CH_2, CH_3, CH_4, CH_5, CH_6, CH_7, CH_8, CH_9 ; 0-9
Отладка в Proteus
К студии 4.19 легко подключить в качестве отладчика Proteus. Это позволяет подавать на схему внешние сигналы и тут же считывать их программой. Или подавая программно сигналы на ножки увидеть их последовательность на цифровом графике, измерить их длительность. Пример того как симулятор показывает сигналы на разрядах дисплея при динамической индикации, эдесь Rat1..Rat8 — разряды, видно что задействовано семь разрядов, восьмой не используется:

Сигналы Tst0, Tst1, Tst2 — это исполнение подпрограмм BINtoPackBCD, PackBCDtoUnpackBCD, UnpackBCDtoSymbolsCode соответственно. На графике они видны черточками, т.к. время их исполнения гораздо меньше цикла 1 сек. Proteus позволяет как угодно раздвинуть график и замерить время исполнения.

Левый (зеленый) курсор ставится левой кнопкой мышки, правый (красный) — той же кнопкой при нажатом CTRL. Внизу в окошке видно время исполнения подпрограммы BINtoPackBCD — 192 мкс.
Идентификатор, дата создания прошивки
Сразу после таблицы прерываний в программе расположен идентификатор.
.ORG INT_VECTORS_SIZE
;------ Идентификатор ----------------------------------------------------------;
Ident: ;
.DB 0, "anakost", 0, __DATE__, 0, CH_v, CH_1 | Seg_H, CH_0, 0
.EQU iSize = (PC - Ident)*2 ; размер идентификатора (в байтах)
.EQU vSize = 3 ; размер информации о версии
;
В нем помещен копирайт, в качестве которого использован ник автора, и дата компиляции прошивки. В НЕХ файле этот идентификатор не видно, т.к. НЕХ это ASCII представление двоичного файла. Зато в бинарном файле этот идентификатор легко найти невооруженным взглядом:

Здесь есть одна тонкость. По умолчанию AVRStudio 4.19 формирует идентификатор даты в виде строки «Jan 29 2015». Это не очень совпадает с российским представлением времени. Чтобы это исправить необходимо установить ISO формат даты в препроцессоре ассемблера. Тогда формат даты примет вид DD.MM.YYYY, где: DD — число, MM — месяц, YYYY — год.
Сделать это несложно, находим меню «Project -> Assembler Options» и открываем настройки ассемблера. В поле «Additional Parameters» вписываем ключ командной строки -FD"%%d.%%m.%%Y". Подробнее в хелпе AVRStudio.
В конце идентификатора расположен номер версии прошивки, в данном случае «v1.0». Версия выводится первые две секунды работы программы, символы представлены в семисегментной кодировке дисплея. Две секунды потому, что в первую секунду результата измерений еще нет, показывать нечего. Интереснее со второй секундой. Дело в том, что генератор с низкочастотным «часовым» кварцем 32768 Гц довольно долго (по компьютерным меркам) выходит на стабильный рабочий режим. Из-за этого первое измерение после запуска будет неверным. Поэтому в программе оно пропускается, отображение результатов начинается со второго.
О выборе регистра флагов для флагового автомата.
В данной программе для регистра флагов выбран регистр из старшей половины адресов. К сожалению такая возможность есть не всегда. Почему именно из старшей половины, можно ли использовать из младшей? К сожалению команды SBR, CBR работают только с регистрами из старшей половины.
Какие еще регистры можно отдать под флаги автомата? Любые из области ввода/вывода. Главное, чтобы их адрес был не более 0х1F (ограничение команд SBI, CBI), они допускали битовую адресацию и не использовались в устройстве.
Я практически не использую блок TWI, и его регистры (TWAR-адреса, TWBR-скорости передачи) идеально подходят для данной цели. Регистр управления TWCR лучше не использовать, т.к. его изменение может включить блок TWI, что приведет к бесконтрольному изменению содержимого других регистров TWI. К счастью регистр управления TWCR и невозможно использовать для флагового автомата, т.к. его адрес 0х36 и команды SBI, CBI с ним работать не будут. С регистром данных TWDR будут, но его лучше не использовать из других соображений, при включении питания все биты будут установлены в 1 и переустановить их можно будет только после первого прерывания. С регистром состояния TWSR тоже будут, но пять битов этого регистра отображают внутреннее состояние блока TWI, один недоступен, для програмирования доступны только два бита.
Практическая замена пар команд SBI < — SBR и CBI < — CBR имеет особенность, команды SBR и CBR принимают в качестве аргумента не номер бита а битовую маску. Команды SBI и CBI принимают в качестве аргумента как раз номер бита, об этом надо помнить. Пары команд SBRS — SBIS и SBRС — SBIС все принимают в качестве аргумента номер бита, замена возможна изменением одной буквы. Если это важно, команды SBR и CBR в два раза быстрее (1 цикл) команд SBI и CBI (2 цикла).
Учтите также что переименование регистров I/O производится не через .DEF, а через .EQU или .SET, примерно так:
.EQU BITx1 = TWAR ; Битовый регистр
P.S. В некоторые новые ревизии AVR чипов добавлены регистры общего назначения (не связанные с внутренними устройствами контроллера) GPIOR0, GPIOR1 и GPIOR2. Их адреса менее 0x1F (у ATtiny2313A, но и у других GPIOR0 этому требованию соответствует), и они идеально подходят для флагового автомата.
Продолжение будет.
Оно будет посвящено работе данной программы с различными контроллерами дисплея. Хотя данное устройство задумывалось как самодостаточное, меня заставил задуматься выхлоп компилятора:

Обидно же, память свободна, а почти все ножки (кроме ISP) заняты. Конечно первое что приходит в голову, применить аналог ATMega8A в корпусе с большим кол-вом ножек. В данном случае прекрасно подойдет ATMega8535. Главное, наличие асинхронного таймера 2 (например в ATMega8515 он отсутствует).
Другой вариант, вместо динамической индикации применить статическую с внешним контроллером дисплея (как в оригинале). Об этом во второй части.
В приложенном архиве FreqDyn.zip проекты AVR Studio и Proteus. Подробнее файл Readme внутри.
P.S. Продолжения доступны:
Часть 2, статическая индикация.
Часть 3, + милливольтметр.
- +6
- 23 декабря 2017, 12:22
- anakost
- 1
Файлы в топике:
FreqDyn.zip
Понравилась идея использовать часовой кварц с асинхронным таймером, обычно в таких вещах тыкают кварц на основную тактовую частоту… А часовой покомпактнее, меньше жрёт и вроде даже точнее.
Меня в очередной раз радует AVR, где от часового кварца работает полноценный таймер, на котором можно сделать что угодно. А не тупо RTC-календарь как во всяких пафосных стм-ках (который, кстати, только мешает, т.к. время в системе всё равно необходимо в нормальном формате скалярного счётчика секунд)…
Меня в очередной раз радует AVR, где от часового кварца работает полноценный таймер, на котором можно сделать что угодно. А не тупо RTC-календарь как во всяких пафосных стм-ках (который, кстати, только мешает, т.к. время в системе всё равно необходимо в нормальном формате скалярного счётчика секунд)…
>> вроде даже точнее.
У меня нет таких данных, здесь представлен не полноценный измерительный прибор, цифровая шкала — это скорее показометр, в данном случае достаточно точный…
У меня нет таких данных, здесь представлен не полноценный измерительный прибор, цифровая шкала — это скорее показометр, в данном случае достаточно точный…
Обычно часовые кварцы идут на 20ppm, высокочастотные — на 30ppm. Можно, конечно, найти более точные, но с вероятностью 99,9% в радиолюбительской конструкции будут стоять самые распространённые стандартные…
Думаю, цифровая шкала вполне может быть измерительным прибором если оценить и указать её погрешность.
Думаю, цифровая шкала вполне может быть измерительным прибором если оценить и указать её погрешность.
А часовой покомпактнее, меньше жрёт и вроде даже точнее.Это бы имело смысл, если бы индикация была не на светодиодный дисплей, а данные таймера захватывались аппаратно, а не в прерывании.
Да и дешевые часовые кварцы та еще гадость с точностью порядка 10^4.
т.к. время в системе всё равно необходимо в нормальном формате скалярного счётчика секундДля этого в пафосных стм-ках есть SysTick.
Это бы имело смысл, если бы индикация была не на светодиодный дисплей, а данные таймера захватывались аппаратно, а не в прерывании.Мне нравится идея использовать часовой кварц для точных интервалов времени, детали реализации уже не суть. Можно и на прерывании точно считать, если оно единственное — никакого джиттера не будет.
Да и дешевые часовые кварцы та еще гадость с точностью порядка 10^4.Дешёвые — это из китайских часов? Хотя 10^-4 — это 9 секунд в сутки, такое найти ещё надо сильно постараться… Кварцы, купленные в магазине или снятые с материнки вполне дают 20ppm.
Для этого в пафосных стм-ках есть SysTick.Теряюсь в догадках какое он вообще отношение может иметь к подсчёту реального времени.
Хотя 10^-4 — это 9 секунд в сутки, такое найти ещё надо сильно постараться…Нет, 10^-4 это 40с в сутки, погрешность самых дешманских китайских часов. Хотя, есть у меня подозрение, что это вообще в чипе косяк. Больно единодушно такие часики косят на 40с, даже в советском исполнении (были у меня и такие, да, электроника что-то-там).
На материнке кварцы явно приличней.
Мне нравится идея использовать часовой кварц для точных интервалов времени, детали реализации уже не суть.Можно хоть атомный стандарт времени взять, если у тебя непредсказуемая задержка входа в прерывание — толку от него не будет.
Сколько помню частотомеров — часовой кварц они не используют, используют точный ВЧ кварц в термостатированной камере, либо более точный источник времени.
Теряюсь в догадках какое он вообще отношение может иметь к подсчёту реального времени.Мы таки о RTC или о счетчике секунд с запуска?
Твои 40с нехарактерны. Такие часы практически невозможно использовать. Типичная ошибка — до пары секунд. В советских часах обычно есть крутилка — подстроечный конденсатор, настроенный на заводе. У таких часов ошибка порядка полсекунды.
если у тебя непредсказуемая задержка входа в прерываниеВ AVR вход в прерывание — 4 такта (не 12, как во всякой хрени) плюс задержка, которую может внести атомарный блок или другое прерывание. В принципе, при необходимости влияние и того и другого можно уменьшить до нескольких тактов или вообще исключить…
Мы таки о RTC или о счетчике секунд с запуска?Причём тут секунды с запуска? прочитай внимательно фразу, которую ты комментишь. Речь про аппаратный RTC-календарь, дурной пережиток, от которого только гемор, который нафиг не нужен. А нужен вместо нормальный монотонный счётчик секунд с начала эпохи. Впрочем, что касается SysTick, для вещей наподобие GetTickCount() он тоже мало пригоден.
Твои 40с нехарактерны.Напротив, крайне характерны. Можешь сам проверить — поищи самые дешманские наручные часы с дисплеем HH:MM, двумя кнопками и без каких-либо допфункций типа будильника — только часы и календарь.
Но действительно, кроме них настолько кривые часы встречаются редко, что наводит на мысль о том, что это таки косяк чипа.
Такие часы практически невозможно использовать.Так и есть, ага.
В советских часах обычно есть крутилка — подстроечный конденсатор, настроенный на заводе. У таких часов ошибка порядка полсекунды.«Электроника» много часов
В AVR вход в прерывание — 4 такта (не 12, как во всякой хрени) плюс задержкаВажна не абсолютная длительность (на нее можно внести поправку — как и на погрешность кварца, кстати), а ее детерминированность.
(не 12, как во всякой хрени)Которая, впрочем, за эти 12 тактов (на втрое большей частоте, так что реального времени они заняли столько же) уже успела регистры схоронить, а не только PC передвинуть.
Причём тут секунды с запуска? прочитай внимательно фразу, которую ты комментишь.Она в достаточной степени неоднозначна. Так что я проинтепретировал ее так, как проинтерпретировал.
А нужен вместо нормальный монотонный счётчик секунд с начала эпохи.Это который переполняется в 2038-м и к которому нужно примерно полкило кода на декодирование его в пригодный для вывода на дисплей формат? В системе он не особо нужен даже при использовании ФС, в ФАТ32 все равно таймштамп в другом формате. А для отсчета интервалов, где и удобно иметь время в виде счетчика — во-первых, точка отсчета времени не важна, а во-вторых — желательно иметь разрешение получше, чем секунда.
Впрочем, что касается SysTick, для вещей наподобие GetTickCount() он тоже мало пригоден.Ну GTC-то в винде на систике и сделан, на самом деле.
Напротив, крайне характерны. Можешь сам проверить — поищи самые дешманские наручные часыИмеют место взаимоисключающие параграфы. «Характерны» и «поищи». У меня дома с десяток часов и я не могу найти такие, которые нужно было бы подводить чаще чем раз в несколько месяцев.
Важна не абсолютная длительность (на нее можно внести поправку — как и на погрешность кварца, кстати), а ее детерминированность.Ну вот я и написал про детерминированность как раз после слов «плюс задержка», на которых ты отсёк цитату.
уже успела регистры схоронить, а не только PC передвинуть.И что с того. Регистров море, ничего не мешает несколько отдать прерыванию, чтобы ничего не сохранять. Да и есть множество прерываний, состоящих из одного SBI/CBI, но которые должны выполниться как можно скорее.
Это который переполняется в 2038-м и к которому нужно примерно полкило кода на декодирование его в пригодный для вывода на дисплей формат? В системе он не особо нужен даже при использовании ФС, в ФАТ32 все равно таймштамп в другом формате. А для отсчета интервалов, где и удобно иметь время в виде счетчика — во-первых, точка отсчета времени не важна, а во-вторых — желательно иметь разрешение получше, чем секунда.Время нужно иметь в виде счётчика, с которым можно работать. Вычислить интервал, сделать коррекцию хода, сменить таймзону, компактно сохранить и т.д. В формате RTC всё это дикий гемор. Даже атомарно загрузить/сохранить время в RTC гемор. Для отображения нужна качественная библиотека, которая переводит системный формат в любое нужное представление, а всякие аппаратные календари — перекладывание с больной головы на здоровую.
«Характерны» и «поищи».Характерны для определенной модели начинки. Я не удивлен, что у тебя в доме нет ни одного образца этого дерьма, хотя и удивлен, что ты с ним не сталкивался. У меня таких с десяток побывало минимум. Могу даже прислать образец, китайцы их до сих пор делают.
Приличные часики, кстати, скорее всего калибруются на заводе, где выбирается погрешность в те самые 20ppm и остается только долговременная стабильность кварца.
Ну вот я и написал про детерминированность как раз после слов «плюс задержка», на которых ты отсёк цитату.Там было «влияние которых можно уменьшить до нескольких тактов». Что уже недетерминированность сравнимая по порядку с нестабильностью кварца.
Регистров море, ничего не мешает несколько отдать прерыванию, чтобы ничего не сохранять.Сильно зависит от задачи. И только при условии что оно такое одно… В ARM7 было FIQ с очень быстрым входом (и при этом без необходимости сохранять регистры) — видимо, оказалось что оно такое не нужно.
И ты уверен что имеенно с этим явлением нужно бороться хранением времени формате RTC, а не time64_t?Зависит от задачи. Аппаратные RTC, причем далеко не только STM'овские (они, по сути, просто встроили в МК типичный аппаратный RTC — попутно забыв главную фичу, резервное питание) обычно хранят именно в таком формате — видимо, на то есть причины.
Там было «влияние которых можно уменьшить до нескольких тактов». Что уже недетерминированность сравнимая по порядку с нестабильностью кварца.Чтобы несколько тактов (абсолютную ошибку) сравнивать с нестабильностью кварца (которая в долях), неплохо бы сперва привести их к общему знаменателю, а то сравнивание малость некорректное…
У anakost-а интервал секунда, тактовая частота 8 МГц, хандлеры явно уложатся тактов в 20. Это даёт ошибку в 5ppm. С нестабильностью кварца оно в принципе сравнимо, но слабым местом оказывается всё таки кварц.
Сильно зависит от задачи.Ну вот я и хочу чтобы в зависимости от задачи можно было выбирать — тратить такты на сохранение или нет.
И только при условии что оно такое одно…Вовсе не обязательно. Можно прерывания делать неблокирующими. Можно выделять окна времени. Иногда бывает такое что прерывание не одно, но вызваться одновременно они никак не могут.
видимо, на то есть причиныЕсли и есть причины хранить время в чудовищно неудобном формате в котором чудовищно геморно его хотя бы сравнить, да и вообще что-то сделать, то причины эти явно не забота о пользователе…
С нестабильностью кварца оно в принципе сравнимо, но слабым местом оказывается всё таки кварцНу, во-первых, 20-30-50ppm — это точность частоты кварца, а не стабильность. Стабильность выше, для нетермостатированного кварца она ЕМНИП приближается к 10^-6, т.е. единицы ppm.
Во-вторых, в корне я писал, что оно сравнимо с разницей между кварцами.
Ну вот я и хочу чтобы в зависимости от задачи можно было выбирать — тратить такты на сохранение или нет.Я бы тоже предпочел иметь возможность выбора, но ее нет ни там, ни там.
Можно прерывания делать неблокирующими.Вот как раз неблокирующие прерывания проблему «на всех регистров не напасешься» только усугубят. С блокирующими можно хотя бы временные регистры иметь общими на все прерывания.
Если и есть причины хранить время в чудовищно неудобном форматеВидимо, не для всех задач он «чудовищно неудобен». ПЛК, кстати, тоже хранят время в таком виде, насколько я помню статьи топикстартера.
Ну GTC-то в винде на систике и сделан, на самом деле.Потому разрешение его — убогие 15мс с копейками… Для МК это никуда не годится.
Ну, уже лучше чем 1000мс разрешения unix time.Ты опять отвечаешь не на коммент, а на то что сам хочешь. Причём тут юникстайм? GTC — это счётчик времени с запуска и комент был о том что систик для его реализации тоже годится хреново. Систик — это прерывание, которое железо дёргает через определённые интервалы времени и в котором ОС решает свои дела. А для GTC хотелось бы чего то попроще, чтобы счётчик инкрементился аппаратно…
А для GTC хотелось бы чего то попроще, чтобы счётчик инкрементился аппаратно…
Справедливости ради, STM32 здесь дает вам сразу несколько вариантов.
Часовой кварц точный, но скорость маловата, соответственно, разрешение системного счетчика будет всего около 30.5 мкс. Иногда надо лучше. Не проблема! Можно сделать программный ремап входа захвата TIM14 на выход часового генератора и просто померять системную частоту относительно часового кварца. После этого можно откалибровать системное тактирование, получив высокоскоростной сигнал с точностью часового. Разумеется, калибровку можно повторять регулярно. Или только при изменении температуры (что можно отследить по встроенному термодатчику). Причем отслеживать можно даже аппаратно — АЦП (который выполняет опрос термодатчика) поддерживает автоматическое определение выхода преобразованного значения за установленные границы… Так что можно установить диапазон температур, при выходе за который прерывание будет запускать процедуру перекалибровки системного тактирования по часовому кварцу.
С другой стороны, если повышенного разрешения не требуется, можно аппаратно подключить выход MCO ко входу почти любого (кроме самых простых из имеющихся внутри) аппаратного таймера и тактировать этот таймер от него. Для MCO можно выбрать любой внутренний сигнал тактирования, и LSE (часовой кварц) в том числе. Так что аппаратный счетчик получается легко и непринужденно.
Все это вы можете почерпнуть из даташита на, скажем, STM32F030F4, который достаточно близок по характеристикам к серии ATmega.
Хороший коммент. Редко от пользователей стм можно увидеть хоть что-то по делу…
Идея с калибровкой мне нравится, если конечно разрешения калибровки хватает для приличной точности…
Идея с калибровкой мне нравится, если конечно разрешения калибровки хватает для приличной точности…
можно аппаратно подключить выход MCO ко входу почти любого (кроме самых простых из имеющихся внутри) аппаратного таймераСнаружи соединять ножки — можно, конечно. Но как-то это не особо изящно и непринуждённо. Что им мешало завести выход LSE на какой-нибудь таймер? Есть множество задач где это может быть полезно. Дурацкий RTC прилепили, а простых и нужных вещей не сделали, даже еепрома нет.
который достаточно близок по характеристикам к серии ATmegaСмотря по каким характеристикам… Скажем, по характеристики «количество страниц ерраты» они весьма далеки.
Ну, использование контроллеров от ST не всегда означает, что человек не уходит дальше STMxxCube. :D
Вообще, я по мере необходимости использую AVR, STM8, MSP430 и STM32 (на работе есть проект даже на ATXmega, и один раз запускал ARM от Atmel, после чего понял, почему их почти не используют). Чаще других применяю AVR и STM32. Реже всего — MSP430 (больно они дорогие). STM8 тоже хороши (в основном ценой, конечно), но под них нет нормального компилятора. Cosmic еще так-сяк, но там непойми что с лицензией, а SDCC — это полная печаль; за IAR хотят денег, много. К GCC соответствующий кодогенератор пока не прикрутили.
Так вот. Самый печалящий меня реальный недостаток STM8/32 — отсутствие нормального встроенного опорного источника (тот, который есть, нельзя использовать как опору АЦП — его можно только мерять!). В этом плане AVR они не конкуренты. Еще AVR безусловно выигрывают по токам GPIO — до 40 мА на ножку, до 200 мА на корпус для ATmega48, например. Так что какой-нибудь вольтметр с семисегментными индикаторами естесственно делать именно на AVR — это сразу минус два корпуса (опорный источник и драйвер дисплея).
Конкретно ATtiny13 — вообще чип-чемпион по соотношению параметров «цена-корпус-возможности». Аналогов ему у ST я не видел.
Что в STM безусловно хорошо — это таймеры. Аппаратная поддержка инкрементального энкодера (очень, очень удобно), комплементарные выходные каналы с настраиваемым защитным интервалом (deadtime), всякие возможности типа аппаратного отключения каналов по внешнему сигналу и так далее.
Очень мощная штука DMA. Самый близкий к народу пример, где DMA приносит ощутимую пользу — управление светодиодами типа WS2812. Без DMA это дико грузит процессор, с DMA и таймером процессор практически простаивает. Конкретных цифр сейчас уже не вспомню и перемерять лень, но помню, что я был потрясен разницей.
32 бита же. :)
Вот ХЗ, на самом деле. Так правда было бы красивее, но, в принципе, дорожка на печатной плате ничего не стоит.
Я бы, к слову, не сказал, что он такой уж дурацкий. Если нужны именно часы — очень удобно. Кстати, модуль RTC там поддерживает пробуждение контроллера по часам и еще несколько возможностей такого сорта, ну а точки во времени удобнее указывать в человекопонятном формате, как минимум, лично мне. Ну а как сделать счетчик аптайма, мы уже разобрались.
Кстати, в состав модуля RTC входит область SRAM, питаемая от батареи, которая может быть сброшена по сигналу с определенной ножки. Удобно для хранения, скажем, ключей шифрования или еще какой-то информации, которую лучше уничтожить при обнаружении физического доступа к устройству.
И главное: модуль RTC не везде одинаковый. Например, в STM32F100 он именно что представляет собой тридцатидвухбитный счетчик, тактируемый через конфигурируемый делитель от линии RTCCLK (ее можно подключить к нескольким источникам). Это то, что вам требуется? :)
Они фон-Неймановские, можно писать прямо во FLASH, в любое место, куда понравится. Так что EEPROM теряет смысл. Кстати вот в STM8 он есть.
Справедливости ради, по сложности некоторых перферийных блоков — тоже. :) Сложнее железо, больше мест для ошибки.
Вообще, я по мере необходимости использую AVR, STM8, MSP430 и STM32 (на работе есть проект даже на ATXmega, и один раз запускал ARM от Atmel, после чего понял, почему их почти не используют). Чаще других применяю AVR и STM32. Реже всего — MSP430 (больно они дорогие). STM8 тоже хороши (в основном ценой, конечно), но под них нет нормального компилятора. Cosmic еще так-сяк, но там непойми что с лицензией, а SDCC — это полная печаль; за IAR хотят денег, много. К GCC соответствующий кодогенератор пока не прикрутили.
Так вот. Самый печалящий меня реальный недостаток STM8/32 — отсутствие нормального встроенного опорного источника (тот, который есть, нельзя использовать как опору АЦП — его можно только мерять!). В этом плане AVR они не конкуренты. Еще AVR безусловно выигрывают по токам GPIO — до 40 мА на ножку, до 200 мА на корпус для ATmega48, например. Так что какой-нибудь вольтметр с семисегментными индикаторами естесственно делать именно на AVR — это сразу минус два корпуса (опорный источник и драйвер дисплея).
Конкретно ATtiny13 — вообще чип-чемпион по соотношению параметров «цена-корпус-возможности». Аналогов ему у ST я не видел.
Что в STM безусловно хорошо — это таймеры. Аппаратная поддержка инкрементального энкодера (очень, очень удобно), комплементарные выходные каналы с настраиваемым защитным интервалом (deadtime), всякие возможности типа аппаратного отключения каналов по внешнему сигналу и так далее.
Очень мощная штука DMA. Самый близкий к народу пример, где DMA приносит ощутимую пользу — управление светодиодами типа WS2812. Без DMA это дико грузит процессор, с DMA и таймером процессор практически простаивает. Конкретных цифр сейчас уже не вспомню и перемерять лень, но помню, что я был потрясен разницей.
если конечно разрешения калибровки хватает для приличной точности…
32 бита же. :)
Что им мешало завести выход LSE на какой-нибудь таймер?
Вот ХЗ, на самом деле. Так правда было бы красивее, но, в принципе, дорожка на печатной плате ничего не стоит.
Дурацкий RTC
Я бы, к слову, не сказал, что он такой уж дурацкий. Если нужны именно часы — очень удобно. Кстати, модуль RTC там поддерживает пробуждение контроллера по часам и еще несколько возможностей такого сорта, ну а точки во времени удобнее указывать в человекопонятном формате, как минимум, лично мне. Ну а как сделать счетчик аптайма, мы уже разобрались.
Кстати, в состав модуля RTC входит область SRAM, питаемая от батареи, которая может быть сброшена по сигналу с определенной ножки. Удобно для хранения, скажем, ключей шифрования или еще какой-то информации, которую лучше уничтожить при обнаружении физического доступа к устройству.
И главное: модуль RTC не везде одинаковый. Например, в STM32F100 он именно что представляет собой тридцатидвухбитный счетчик, тактируемый через конфигурируемый делитель от линии RTCCLK (ее можно подключить к нескольким источникам). Это то, что вам требуется? :)
даже еепрома нет
Они фон-Неймановские, можно писать прямо во FLASH, в любое место, куда понравится. Так что EEPROM теряет смысл. Кстати вот в STM8 он есть.
по характеристики «количество страниц ерраты» они весьма далеки.
Справедливости ради, по сложности некоторых перферийных блоков — тоже. :) Сложнее железо, больше мест для ошибки.
Кстати, в состав модуля RTC входит область SRAM, питаемая от батареиО, там есть батарейный домен? В F100 это больше всего удивляло в RTC — оно есть, но его нельзя запитать от батарейки! Как так-то?!
Так что EEPROM теряет смысл.Если не требуется часто писать.
Только input capture.Остается только вопрос — нафига каптурить MCO…
Конкретно ATtiny13 — вообще чип-чемпион по соотношению параметров «цена-корпус-возможности». Аналогов ему у ST я не видел.tiny13 — супер. Можно ещё глянуть tiny5/10 — похожи на tiny13, но на борту большой 16-битный таймер, с которого можно брать двухфазный сигнал, менять его частоту и коэффициент заполнения в широких пределах (причём коэффициент заполнения — это не дедтайм, его можно менять от 0 до 100/50%). Правда программирование TPI, а не SPI. Но собрать программатор не проблема, протокол описан в даташите.
Очень мощная штука DMA.Да, STM32 несмотря на всю свою уродливость вывозят за счёт быстрых команд, тактовой частоты и DMA. Правда и здесь есть по хорошему ушату помоев. В DMA — реквесты фиксировано замаплены на несколько источников, и включив один источник остальные уже использовать нельзя. Только в F3+ исправлено. Что до быстрого ядра — впечатление портит тормозной флеш. SRAM тоже не решает проблему — её мало и к ней нужно обращаться за данными (в F3+ правда есть немножко CCM, да). Также очень большой минус — кривой и неудобный ассемблер. Без ассемблера не раскроешь мощь ядра по полной, что бы там не вопили любители ЯВУ.
Я бы, к слову, не сказал, что он такой уж дурацкий. Если нужны именно часы — очень удобно.Я уже сделал простые часики, если буду делать ещё — будет синхронизация по NTP и ещё что-нибудь. Да и в простых была коррекция хода, прилепить её к RTC геморно. Да и вообще подход с календарным RTC — отстой. В технике время — это линейно нарастающая скалярная величина, именно так с ней работать удобно и правильно. Астрономическое время нужно только для ввода-вывода в интерфейсах, именно там оно и должно преобразоваываться в/из этот формата. ДОС хранил астрономическое время, но от того давно отказались. В линуксе используется скаляр time_t (который правда должен перепониться в 2032-м, но все давно уже перешли на time64_t). В винде время изначально 64 бита, причём разрешение аж наносекунда. Но СТ зачем-то решили выкопать труп древнего календарного RTC.
Кстати, в состав модуля RTC входит область SRAM, питаемая от батареи, которая может быть сброшена по сигналу с определенной ножки.Насколько я помню еррату, оно не работает. По крайней мере, в тех семействах, которые я смотрел (F0, F4). То ли сбрасывается самопроизвольно, то ли не сбрасывается когда надо…
И главное: модуль RTC не везде одинаковый. Например, в STM32F100 он именно что представляет собой тридцатидвухбитный счетчик, тактируемый через конфигурируемый делитель от линии RTCCLK (ее можно подключить к нескольким источникам). Это то, что вам требуется? :)Это безусловно плюс. Хотя именно на мелких сериях календарный RTC может быть хоть как-то оправдан (примитивные чясики без ЦКХ?), но календарный RTC стоит как раз на сериях пожирнее. Который в соответствующих жирных задачах любом случае придётся конвертировать в нормальный скаляр при чтении и в календарь при записи. И ещё ломать голову как сделать это атомарно…
Они фон-Неймановские, можно писать прямо во FLASH, в любое место, куда понравится. Так что EEPROM теряет смысл.Флешка стирается только страничками. Что уже не очень удобно само по себе. И ресурс у флеша меньше в 10 раз, а переписывать нужно большую страницу на любое изменение.
STM8 тоже хороши (в основном ценой, конечно)Вот именно, что лишь ценой. В остальном одно уныние. И ядро и периферия и элекртические параметры и как всё это сделано. Посмотреть хотя бы на время выполнения команд и количество регистров, какой-то простенький пик напоминает. Нет моих любимых умножений с длинным результатом. Это только один пример из большого множества.
причём коэффициент заполнения — это не дедтайм, его можно менять от 0 до 100/50%
Не, ну в том таймере, о котором я говорил, коэффициент заполнения, естесственно, тоже можно менять. :D Я об этом не писал как об очевидном.
Кстати защитный интервал там тоже можно настраивать по вкусу. А еще полярность выходов и много-много всего.
Правда программирование TPI, а не SPI.
Да, именно поэтому я до этих прикольных чипов пока что так и не добрался. Хотя AVRISP-mkII поддерживает его, вроде бы. А еще они больно дорогие в местных магазинах… Стоили бы они по 30 — 50 р., как серия F030, было бы интереснее.
Да, STM32 несмотря на всю свою уродливость
Здесь есть нюанс. Если вы вчитаетесь в документацию на разные серии (да хотя бы F100 и F0xx), вы сразу поймете, что это по большей части разные контроллеры. Разгадка проста — их делали разные люди. Мне рассказывали инсайдерскую информацию насчет того, что после F100 в ST просто разогнали дизайн-отдел и набрали его заново.
Так что документацию на STM32 надо читать ОЧЕНЬ внимательно. Сколько бы ни кричали представители ST и их адепты про фантастическое единство и полную взаимозаменяемость чипов всей линейки, это неправда. Серия STM32 на деле состоит из достаточно разных чипов, и это надо учитывать.
Ну и да, в некоторых местах документация не блещет прозрачностью, что есть, то есть…
Также очень большой минус — кривой и неудобный ассемблер. Без ассемблера не раскроешь мощь ядра по полной, что бы там не вопили любители ЯВУ.
Здесь, опять же, есть нюанс. Для чипов на ARM надо применять немного другую парадигму разработки. Лезть руками в тамошний ассемблер нет особого смысла уже потому, что за счет системы предвыборки команд из FLASH (ART accelerator), серьезного конвейера и out-of-order execution время выполнения команд и очередность доступа к памяти (кроме выделенных областей), вообще говоря, непредсказуемы (так что, например, писать на ассемблере Cortex-M3 протокол 1-Wire я бы не стал). Ну, если только не ставить после каждой инструкции data memory barrier.
Так что здесь действительно правильно оставить ручную генерацию ассемблерного кода и просто надеяться, что компилятор и система выполнения кода выжмут максимум. Чаще всего оно так и будет.
Сила этих чипов — мощная периферия, которая может делать многое просто сама по себе (как, например, АЦП, автоматически проверяющий преобразованное значение на попадание в диапазон). Потому все задачи, критичные к таймингам, надо перекладывать на нее. Возвращаясь к примеру с 1-Wire — на STM32 его логично реализовывать на базе UART. Их там много, потому один вполне можно отдать под 1-Wire, и это не ударит по ресурсам так, как это было бы в AVR, скажем.
То есть идеал — настроил периферию, она сама работает, а ядро вообще выключено.
Немного другой подход, немного другая парадигма. Непривычная, да.
В DMA — реквесты фиксировано замаплены на несколько источников, и включив один источник остальные уже использовать нельзя.
Нельзя на одном канале. На других можно. Недостающее можно ремапить.
прилепить её к RTC геморно
Конкретно в STM32F051 для этой цели есть RTC_SHIFTR, который позволяет аккуратненько двигать часы с субсекундным разрешением.
Да и вообще подход с календарным RTC — отстой. В технике время — это линейно нарастающая скалярная величина, именно так с ней работать удобно и правильно.
Ну, это все же субъективно. Удобно — это как когда. Чем тащить в контроллер библиотеку, которая будет корректно обрабатывать все это (сколько десятков килобайт она займет?), проще иметь аппаратный модуль RTC с календарем…
Насколько я помню еррату
На какой чип? В errata на STM32F100 про это я ничего не нашел.
Если говорить про F0, то там ошибка совершенно смешная. Кому может понадобиться программно выключать tamper detection, если уж ее включили? Обычно в таких случаях функционал конфигурируется раз и надолго.
И ещё ломать голову как сделать это атомарно…
Ломать голову не надо. Теневое копирование уже реализовано за вас, аппаратно.
И ядро и периферия и элекртические параметры и как всё это сделано.
Ага. До сих пор ржу с их регистра установки скорости UART (по-моему, дело было с STM8S103F3). У меня только один вопрос: ПОЧЕМУ ТАК? :D Зато они дешевые.
Кстати защитный интервал там тоже можно настраивать по вкусу.Не могу сказать что это хорошо, можно и самому ограничивать коэффициент заполнения. Больше сложность периферии — больше ошибок в ней, а пользы особой нет… Не люблю когда в железе лепят то что элементарно, без всяких издержек делается программно в пару операторов или строк просто чтоб оно было. Заканчивается это «много всего» потерей гибкости, более громоздким кодом и ерратой.
Стоили бы они по 30 — 50 р., как серия F030, было бы интереснее.Много говорят про дешёвый стм, но не видел я чтобы они были намного дешевле. В компэле ATtiny10 — 33р, в чиде — 43р. Не так уж это много. Для радиолюбителя, собирающего несколько устройств в год для себя это даже копейками назвать нельзя. Нужно изготавливать много тысяч экземпляров чтобы эта несчастная разница в цене могла хоть в малейшей мере проявиться.
Мне рассказывали инсайдерскую информацию насчет того, что после F100 в ST просто разогнали дизайн-отдел и набрали его заново.Это супер! Бывает в мире справедливость — хоть иногда, но гоняют тех кто делает такие вещи. Но по большей части МК остались теми же, в следующих сериях часть убожеств исправили, но с нуля всё не переделали… Им бы ещё тех кто документацию пишет разогнать, да переписать по человечески. Документация очепятками пестрит (типа TIMM1_BK1N вместо TIM1_BKIN), не говоря уж про остальное…
Так что здесь действительно правильно оставить ручную генерацию ассемблерного кода и просто надеяться, что компилятор и система выполнения кода выжмут максимум. Чаще всего оно так и будет.Скорее всего не будет. Компиляторы неплохо справляются с тривиальными линейными кусками, там где ещё надо постараться сделать неоптимально. И неплохо вытягивают на учёте особенностей исполнения. Но когда структура кода становится маломальски разветвлённой, изучение выхлопа компилятора вызывает лишь уныние и желание всё переписать самому. С алокацией регистров компиляторы тоже не особо сильны. Это те вещи где нужно видеть картину в целом и кучка правил зашитых в компиляторы не вытягивают — тут нужна работа интеллекта. До полноценного ИИ компилятором далеко. Что касается avr-gcc, его выхлоп от любого кода, даже самого примитивного вызывает непрекращающийся фейспалм. Написанный вручную код как правило 4 и более раз быстрее и гораздо компактнее. Может отсюда у меня тяга к переписыванию критических участков на ассемблере. Впрочем, и на x86 это давало результат (и более акуратный код в случае с SIMD — не люблю мешанину Си с интринсиками, уж лучше кусочек написать на асме).
Сила этих чипов — мощная периферия, которая может делать многое просто сама по себе (как, например, АЦП, автоматически проверяющий преобразованное значение на попадание в диапазон).Это мне тоже не особо нравится. Я бы результаты АЦП сперва через медианно-усредняющий фильтр пропустил. Тут также как с RTC — очень большая потеря гибкости. Хотя в отличие от RTC хотя бы маломальски оправданная если нужно делать быстро.
Ну, это все же субъективно. Удобно — это как когда. Чем тащить в контроллер библиотеку, которая будет корректно обрабатывать все это (сколько десятков килобайт она займет?), проще иметь аппаратный модуль RTC с календарем…Удобно — практически всегда. Сравнить, отсортировать, вычислить интервал, компактно сохранить, передать, преобразовать в любой формат. Просто правильнее. Библиотеки есть. Функциональнасть аппаратного RTC не та, чтобы для его замены требовалась программная библиотека на десятки килобайт.
Если говорить про F0, то там ошибка совершенно смешная. Кому может понадобиться программно выключать tamper detection, если уж ее включили? Обычно в таких случаях функционал конфигурируется раз и надолго.Не помню точно, вроде было аж две ошибки связанные с тампер-детектом. Что в F0, что в F4…
Ломать голову не надо. Теневое копирование уже реализовано за вас, аппаратно.Но открываем еррату — и, сюрприз, оно не работает. О чём я и говорю. Бессмысленные навороты в аппаратных блоках «чтоб было» ведёт к еррате и раздутому коду. Причём без особой пользы для кого-либо.
Не могу сказать что это хорошо, можно и самому ограничивать коэффициент заполнения.
Вы немного не поняли. Таймер, о котором я говорю, немного более продвинут, чем вы себе представляете. :)
Ограничение коэффициента заполнения сработает, если используются два канала ШИМ. Тогда, действительно, можно следить, чтобы значения не перекрывались (и не оказывались слишком рядом).
В STM32 описанное реализуется одним каналом сравнения. То есть, коэффициент заполнения задается один, и из него получается два выходных сигнала: один как есть, а второй комплементарный, задержанный на указанное время (защитный интервал).
Такие дела.
Много говорят про дешёвый стм, но не видел я чтобы они были намного дешевле.
Вот пара примерных аналогов:
STM32F030F4 — 48 руб.
ATmega168PA-AU — 140 руб.
Почти в три раза…
Для радиолюбителя, собирающего несколько устройств в год для себя это даже копейками назвать нельзя.
В сущности, да. Тут уже дело в том, что я, э-э-э, не совсем любитель. Ну а для себя в таком случае проще использовать то, с чем и так работаешь.
Написанный вручную код как правило 4 и более раз быстрее и гораздо компактнее.
Здесь есть искушение попросить какой-нибудь стоящий пример. Скажем, ваши варианты FFT на Си и на ассемблере. Или сравнение реализаций чего-нибудь в духе LU-разложения, обращения матрицы, решения СЛАУ, свертки, на худой конец.
Я бы результаты АЦП сперва через медианно-усредняющий фильтр пропустил.
Зависит от применения. Когда я ловил резкие скачки значений с датчика тока для того, чтобы обрабатывать тиристорное защелкивание при испытаниях мс на воздействие тяжелых заряженных частиц, медианный фильтр был мне совсем не в тему…
Ну и никто не заставляет использовать именно эту фичу. Можно, скажем, с помощью циклического режима DMA складывать этак по десятку значений в память, а дальше по прерываниям half transfer/full transfer быстро их усреднять и уже тогда, в прерывании, делать вывод. Все равно экономия времени за счет того, что прерывание вызывается не после каждой выборки.
Просто правильнее.
Это не технический аргумент. :) Это, знаете ли, гуманитарии могут спокойно аргументировать, что, например, так играть Шопена, как они, «просто правильнее», потому что они так видят. :)
А у нас есть четкий критерий — объем кода. И аппаратный блок RTC с календарем его очень сокращает. Не нужен календарь? Возьмите чип без календаря! Нужен и календарь, и счетчик UNIX time? Возьмите чип с календарем и затактируйте один из счетчиков от LSE!
Проблемы ведь, на самом деле, просто нет. Каждому применению — свой чип.
преобразовать в любой формат
Вы же смотрели то видео, ссылку на которое я давал? :)
Не помню точно, вроде было аж две ошибки связанные с тампер-детектом.
Они связаны с настройкой и никак не влияют на собственно функционал. Написали просто для полноты картины.
Вы немного не поняли. Таймер, о котором я говорю, немного более продвинут, чем вы себе представляете. :)Таймеры в хвалёном стм я более-менее себе представляю. Но продвинутым назвал бы, например, TC1 в ATtinyX61A. А таймеры у стм скорее вполне обычные…
В STM32 описанное реализуется одним каналом сравнения.Не совсем описанное. Когда я говорил про ATtiny5/10, я имел в виду двухфазный сигнал, т.е. типа пуш-пулл — симметричный с регулировкой коэффициента заполнения. Не получишь его на одном канале в хвалёном стм…
Здесь есть искушение попросить какой-нибудь стоящий пример. Скажем, ваши варианты FFT на Си и на ассемблере.Что касается AVR, я не вижу смысла писать FFT на Си, т.к. заранее знаю что получится тормозное кошмарище. Я сразу пишу на ассемблере. Си не способен работать с фикседпойнтом, на этом можно остановиться (а в хвалёном стм8 и асм не поможет). То о чём я говорю — статистика, набранная на различных случаях из практики. Написал критичный кусочек на Си, посмотрел на убожество полученного кода и время его выполнения (в AVRStudio это зачастую можно быстренько сделать в симуляторе, а в стм32 — видимо только бенчмарки в железе — скажем, в иаре в симуляторе я так и не нашёл счётчика тактов), понял что дофига не оптимально — переписал на асм, поразился результату. Запомнил что такое надо писать сразу на асме. Даже простое прерывание, скажем, системного счётчика микросекунд и миллисекунд при тактировании от кварца на 14.7456 на асме получается раза в 2.5 раза быстрее. Более заковыристые куски запросто дают 4 раза и более…
Когда я ловил резкие скачки значений с датчика токаКстати, банального компаратора в стм тоже не положили. Чем они думали? Иногда очень полезно для быстрой реакции на аварийные события. Скажем, в упомянутой мной ATtinyX61A компаратор даже можно использовать совместно с TC1 для защиты — видно, что люди думали прежде чем делать…
а дальше по прерываниям half transfer/full transfer быстро их усреднять и уже тогда, в прерывании, делать выводКстати, эти half transfer/full transfer — то ещё убожество… Работа с буферами в DMA меня разочаровала, от хвалёного продвинутого МК я ожидал поддержку полноценного кольцевого буфера с гистерезисами заполнения.
Это не технический аргумент.Правильную декомпозицию систему на уровни я ценю и для меня это вполне технический аргумент. Она сильно облегачает жизнь, позволяет строить систему легко и непринуждённо. Время в системе не скаляром — как раз архитектурно неверное решение… Многие простейшие и базовые действия превращаются в неотпимальный кошмар. При том, что особого выигрыша нет. В Си есть стандартная библиотека sys/time.h, которая тебе спокойно распакует time_t в struct tm. Говорить тут про объём кода смешно.
Вы же смотрели то видео, ссылку на которое я давал? :)Догадываюсь о том чего там расскажут. Только едва ли аппаратный RTC в стм умён как библиотека на десятки килобайт.
Когда я говорил про ATtiny5/10, я имел в виду двухфазный сигнал, т.е. типа пуш-пулл — симметричный с регулировкой коэффициента заполнения. Не получишь его на одном канале в хвалёном стм…
Прямо сейчас на столе у меня лежит устройство, которое генерирует именно такой сигнал на одном канале таймера 1 в STM32F030F4P6. Код инициализации (взят прямо из проекта):
/** TIM1 setup for complementary PWM on pin PA10/TIM1_CH3 & PB1/TIM1_CH3N */
TIM1->CCMR2=TIM_CCMR2_OC3PE | TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1; //Fast PWM on TIM1_CH3
TIM1->BDTR=TIM_BDTR_MOE | DEADTIME_CONF;
TIM1->PSC=PWM_PRESCALER;
TIM1->ARR=PWM_ARR;
TIM1->CCR3=0;
TIM1->CNT=0;
TIM1->CCER=TIM_CCER_CC3E | TIM_CCER_CC3NE; //Enable complementary output
TIM1->CR1=TIM_CR1_ARPE | TIM_CR1_CEN;
TIM1->EGR=TIM_EGR_UG;
На выходе (PA10/PB1) именно push-pull сигнал. Коэффициент заполнения управляется значением TIM1_CCR3 (да, сразу для двух каналов с учетом защитного интервала).
Кстати, банального компаратора в стм тоже не положили.
Вы постоянно обобщаете применительно к каким-то абстрактным STM32, в то время как я уже не раз указывал, что это семейство негомогенно, вопреки заверениям маркетологов ST. Пожалуйста, уточняйте, о каком кристалле идет речь…
Скажем, в упомянутой мной ATtinyX61A компаратор даже можно использовать совместно с TC1 для защиты — видно, что люди думали прежде чем делать…
В STM32L152, например, компараторов целых два, и, не поверите, их тоже можно использовать для защиты:
The COMP2 output can be redirected to TIM2/TIM3/TIM4’s input capture 4 (IC4) or OCREF_CLR inputs, or to the TIM10s input capture 1 (IC1). — см. даташит.
Более того, из этих двух компараторов можно собрать оконную схему, выбрать из нескольких предустановленных уровней опорного напряжения или вообще использовать ЦАП для опоры, и т.д., и т.п.
На компараторах и таймерах рассматриваемого чипа вполне можно собрать аналог MC33063, который будет работать сам по себе, автономно от основной системы.
В Си есть стандартная библиотека sys/time.h, которая тебе спокойно распакует time_t в struct tm.
И сколько оно занимает в памяти МК?
Прямо сейчас на столе у меня лежит устройство, которое генерирует именно такой сигнал на одном канале таймера 1 в STM32F030F4P6.Увы, не понимаю за счёт чего в этом примере формируется двухфазный сигнал. На всякий случай уточню что я под ним понимаю…

Пожалуйста, уточняйте, о каком кристалле идет речь…F1. Да, в данном случае уже исправили. Молодцы.
И сколько оно занимает в памяти МК?Скомпилировал такую заглушку под STM32F1.
int main() {
time_t test = 1515251301;
gmtime(&test);
return 0;
}
Объём test.bin вырос на 1800 байт где-то. А какая нафиг разница? Если проект — простые часики, то флеша с избытком и из-за этих несчастных полутора килобайт за лимит никак не вылезешь. Если задача хоть на миллиграмм сложнее, от конвертаций всё равно ни за что не отделаться. Любая работа со временем (кроме вывода на семисегментники в часиках) не в скаляре крайне неоптимальна. Потому и используется time_t в линупсе, FILETIME в винде…
Да-да, сигнал именно такой, как на картинке. Генерация такого сигнала — стандартная возможность некоторых каналов в таймерах STM32.
В том отрывке кода, который я привел, я включаю комплементарный канал (бит TIM_CCER_CC3NE), после чего просто задаю ненулевой защитный интервал (DEADTIME_CONF — дефайн, объявленный выше по тексту программы).
Ну и как бы все. Остальное стандартная настройка режима ШИМ, включение генерации сигнала (TIM1_BDTR_MOE) и так далее. Естесственно, в полной программе есть еще настройка GPIO и тактирования.
Да, действительно все так просто. И не нужны никакие STM32Cube и прочие HAL с StdPeriphLib. Просто надо внимательно читать даташит.
В том отрывке кода, который я привел, я включаю комплементарный канал (бит TIM_CCER_CC3NE), после чего просто задаю ненулевой защитный интервал (DEADTIME_CONF — дефайн, объявленный выше по тексту программы).
Ну и как бы все. Остальное стандартная настройка режима ШИМ, включение генерации сигнала (TIM1_BDTR_MOE) и так далее. Естесственно, в полной программе есть еще настройка GPIO и тактирования.
Да, действительно все так просто. И не нужны никакие STM32Cube и прочие HAL с StdPeriphLib. Просто надо внимательно читать даташит.
Всё это не очень понятно… Включаю Fast PWM, комплиментарный выход, настраиваю дедтайм и оно сразу выдаёт двухфазный сигнал? Т.е. нормальный пуш-пулл как TL494? А какую роль играет дедтайм?

А потом включаю инверсию одного канала и оно превращается в простой однофазный ШИМ (как и ожидается при настройке в режиме простого ШИМ)?

Странное поведение. В даташите я даже намёка на подобное не вижу…

А потом включаю инверсию одного канала и оно превращается в простой однофазный ШИМ (как и ожидается при настройке в режиме простого ШИМ)?

Странное поведение. В даташите я даже намёка на подобное не вижу…
Вы предлагаете мне за вас углубиться в даташит и поэкспериментировать, чтобы развеять ваши сомнения? :) Честно, мне лень. Сейчас мне не нужен этот режим. Когда понадобится — освою. Вполне вероятно, что я неправильно вспомнил бит, который нужно выставить. Я использовал только комплементарный режим.
Там есть еще куча бит, которые отвечают за огромное количество возможностей. Всех их наизусть я, понятное дело, не помню.
Но в любом случае, таймер 1, например, имеет четыре ШИМ-канала с управляемой инверсией, которые, естесственно, можно задействовать одновременно в любой комбинации. Так что если и не с одного канала, то с двух можно получить любой сигнал. Это то, что я могу сказать навскидку.
Там есть еще куча бит, которые отвечают за огромное количество возможностей. Всех их наизусть я, понятное дело, не помню.
Но в любом случае, таймер 1, например, имеет четыре ШИМ-канала с управляемой инверсией, которые, естесственно, можно задействовать одновременно в любой комбинации. Так что если и не с одного канала, то с двух можно получить любой сигнал. Это то, что я могу сказать навскидку.
Ух-ух, какие мы важные — даже стм32 изучили па даташиту и поучаем ДАЖЕ самого Лайфловера. Я не знаю, кто щас эти люди, но лет 5-6 назад, как я помню — Лайфловер был студент 1-2 курса, а этот ДЯДЯ был окончивший юниверситет молодой препод, но тупой, как пробка тогда в електронике. Хе-хе, или я в чем-то ошибаюсь?
- well-man2000
- 07 января 2018, 01:54
- ↑
- ↓
Ну значит я ошибся, но почему-то все_равно_щитал, что ты електронный унтерменш. Ну тогда есно,
Лет пять-шесть назад, ха-ха-ха!
- well-man2000
- 07 января 2018, 02:10
- ↑
- ↓
всем, кто что-то знаетДа, я завидую тебе… и моему дорогому другу evsi, хнык-хнык-хнык…
- well-man2000
- 07 января 2018, 02:15
- ↑
- ↓
4 года уж прошлоУх ты, с большим удовольствием перечитал… Да-а, а Я явно раньше был ГОЛОВА — точно умнее и пассионарнее, чем щас.
VGA, ты зачем это запостил? Гы-ы, ты мазохист, или же просто хотел пропиарить МЕНЯ! :DDD
- well-man2000
- 07 января 2018, 13:24
- ↑
- ↓
Там есть еще куча бит, которые отвечают за огромное количество возможностей.Моё впечатление — стм создавали методом копипасты. Т.е. дезигнерам была поставлена задача «сделайте всё, что есть у других». Совсем не удивлюсь, услышав такую «инсайдерскую инфу». Мне больше по душе МК, которые создавались осмысленно.
Так что если и не с одного канала, то с двух можно получить любой сигнал.Да ладно. По фазе оно сколочно гвоздями краями или серединками и ничего с этим не сделаешь. Так что далеко не любой. Хотя при такой сложности могли бы и погибче сделать, чтобы фазу можно было двигать произвольно…
А, до меня дошло, чего вы хотите. Картинки не совсем удачные. Я наконец-то прочел подписи на них. :DНе знаю как можно удачней нарисовать. И я же сразу сказал — пуш-пулл. Разница между ним и однотактником вроде должна быть очевидна.
Моё впечатление — стм создавали методом копипасты. Т.е. дезигнерам была поставлена задача «сделайте всё, что есть у других»
> «Брат, прими хазават — Бог велит!» Л, Н.Толстой «Хаджи-Мурат».
Решил все же взяться за старый-добрый олдскульный RISC (ARM), маладэсъ! Кстати, в ARM Cortex-M3 в своё время (2009) инженеры-энтузиасты из Luminary решили использовать самое старое и якобы нахуй никому не нужное ядро ARM 1-й или 2-й версии ещё 80-х годов из 40-50 тыс транзисторов.
И сиим дополнительно подняли бабло этой британской конторе буквально из
В любом случае, щас эта паразитическая британская говно-контора (ARM) уже нравится не всем из-за своей жадности и частичной проприетарстности. И многие уже посматривают на RISC V. Мир уже готов к эпохе возвращения старых примитивных и быстрых ядер.
- well-man2000
- 07 января 2018, 14:13
- ↑
- ↓
инженеры-энтузиасты из Luminary решили использовать самое старое и якобы нахуй никому не нужное ядро ARM 1-й или 2-й версии ещё 80-х годов из 40-50 тыс транзисторов.ARMv2 не запатентован, так что если тебя не смущает необходимость писать микроархитектуру с нуля — можешь пилить его не плятя ARM Holdings ни копейки. Собственно, даже писать необязательно — есть Amber.
И сиим дополнительно подняли бабло этой британской конторе буквально из говна нуля.Поясни-ка этот пункт. В 2009 ARM уже активно завоевывал рынок микроконтроллеров, а взлетели они за счет сотовых телефонов.
Телефоны и ARM7tdmi — это другая тема. Мы говорим здесь о MCU на кортексах, это ещё более примитивное и дешевое ядро, чем арм7tdmi. Ты видимо вспомнил NXP LPC24xx и т.п. на ARM7tdmi — это тупиковая попытка арма, настоящий успех пришёл к люминари с кортексом м3.
- well-man2000
- 07 января 2018, 14:55
- ↑
- ↓
Luminary в 2009-м была куплена TI (mcu Stellaris). Я ошибся — уже в 2006/7-м году они пиарили свой 32-бит mcu LM3 на ядре кортекс м3 по цене $1 (цена, есно, оптовая — для производителей). Это была первая фирма, которая создала и продвигала 32 бит mcu на кортексе. Все остальное быдло — nxp, stm и ti — прочухли тему уже позже и срочно подтянулись.
- well-man2000
- 07 января 2018, 15:51
- ↑
- ↓
Где существовал см3 5 лет? — не надо бредить. возможно, что в 2004/5 они создали технологию в лаборатории, «на коленке» — это ещё не значит, что это все было готово к пром.выпуску, а маркетинг (этот факин капитализм), а ПО, что ещё более важно для этой отрасли.
- well-man2000
- 07 января 2018, 16:25
- ↑
- ↓
Я пользуясь вики, но не верю ей, если у меня есть другие сведения/источники. основа ядра см3 более древнее и более примитивное, чем ARM7TDMI, т.е. более эффективное по кол-ву вентилей и более дешевое, иначе — в mcu так и продвигался бы и далее ARM7TDMI.
- well-man2000
- 07 января 2018, 16:38
- ↑
- ↓
Ты думаешь, что я пишу здеся для тебя — зануды? Нет, для ЛЮДЕЙ — они сами разберутся и поймут, если надо (по крайней мере, гугель у каждого под рукой — luminary $1 microcontroller).
- well-man2000
- 07 января 2018, 16:56
- ↑
- ↓
Да, по-видимому, в железе CM3 вышел только в конце 2006 в виде LM3S101, спустя год после появления не-конфиденциальной документации на ядро. В середине 2007 подтянулась и STM.
Тем не менее, судя по этой статье, даже спустя два-три года выбор CM3 vs ARM7 был совсем не очевиден.
Тем не менее, судя по этой статье, даже спустя два-три года выбор CM3 vs ARM7 был совсем не очевиден.
И ваще, разработка этого проца и сам принцип RISC и присущая ему сист.команд были сделаны в САСШ, по-моему в Беркли, профессорами энтузиастами и их студентами. Было много шума в 80-х, но индустрия САСШ — положила на них хуй, т.к. тогда на мази в области CPU были 2 конкурирующие CISC архитектуры — это православная Моторола 68000 и задроченное, говенное, но пропиаренное гумно в виде Интел 8086.
Потом, это тупое и ничего не знающее чмо из Acorn кампутер, финансируемое из британской гос.казны (как и BBC) — говно-кампутер (аналог Эппл-I) на знаменитом нищебродском 8-бит проце MOS Tec 6502, заявило свою тупую, дебильную, британскую харю в Беркли (эти мартышки до этого продавали аудио-усилители в наборах, и «проектировали» знаменитый говнокомп «Лорда» Синклера). В поисках КРУТОГО и дешевого проца, есно. Ну а те лошары пиндосские (чо паделать — ботаны/совки) слили этим британским тупицам технологию за сущие копейки.
Вот така и паявилася эта фирмА под названием ARM. Мартышки долго бедствовали и не знали, как свести концы с концами, но примитивная, есно, нисколько не развиваемая этими британскими полудебилами технология, ВДРУГ, дожила до тех времен, когда был нужен малопотребляющий проц в портативных девайсах.
Потом, это тупое и ничего не знающее чмо из Acorn кампутер, финансируемое из британской гос.казны (как и BBC) — говно-кампутер (аналог Эппл-I) на знаменитом нищебродском 8-бит проце MOS Tec 6502, заявило свою тупую, дебильную, британскую харю в Беркли (эти мартышки до этого продавали аудио-усилители в наборах, и «проектировали» знаменитый говнокомп «Лорда» Синклера). В поисках КРУТОГО и дешевого проца, есно. Ну а те лошары пиндосские (чо паделать — ботаны/совки) слили этим британским тупицам технологию за сущие копейки.
Вот така и паявилася эта фирмА под названием ARM. Мартышки долго бедствовали и не знали, как свести концы с концами, но примитивная, есно, нисколько не развиваемая этими британскими полудебилами технология, ВДРУГ, дожила до тех времен, когда был нужен малопотребляющий проц в портативных девайсах.
- well-man2000
- 07 января 2018, 21:24
- ↑
- ↓
Чо, круто написано! :DDD Да-а, такого не достигнуть без допинга… Самое интересное, что все это — правда, но конечно же в специфической упаковке…
- well-man2000
- 07 января 2018, 21:50
- ↑
- ↓
Чо, круто написано!Вы слишком высокого мнения о своей писанине.
Да-а, такого не достигнуть без допинга…Судя по стилистике вашего бреда, допингом вам служил низкокачественный алкоголь в больших количествах.
Самое интересное, что все это — правда, но конечно же в специфической упаковке…Все написаное вами не более чем ваше предвзятое мнение.
По фазе оно сколочно гвоздями краями или серединками и ничего с этим не сделаешь.Точно. Причем это справедливо для любой реализации PWM на счетчиках.
Хотя при такой сложности могли бы и погибче сделать, чтобы фазу можно было двигать произвольно…Даже интересно, как вы себе это представляете? Особенно учитывая, что фаза как таковая появляется только в тот момент, когда принимается решение от чего эту самую фазу отсчитывать.
P.S. учитывая, что таймеры можно грузить через DMA, то сгенерировать можно практически что угодно. внимательное изучение, General Purpose Cookbook вполне может помочь тому, кто в этом хочет разобраться. Правда, насчет вас я сильно сомневаюсь, что вы хотите в этом разбираться, а не просто традиционно поливать дерьмом.
вы сильно недооцениваете оптимизаторы. Даже SDCC не требует написания на ассемблере, несмотря на то, что оптимизатор в нём описываемого вами уровня (практически никакой). Добавить пару ключевых слов, немного изменить структуру Си кода и мы получаем генерацию оптимального АСМ кода при сохранении читаемости программы.
асм имеет смыл в очень узкой нише, где такая жёсткая оптимизация оправдана (как та же программная реализация юсб), но это признак ошибки выбора целевой платформы.
асм имеет смыл в очень узкой нише, где такая жёсткая оптимизация оправдана (как та же программная реализация юсб), но это признак ошибки выбора целевой платформы.
Если вдруг Вам понадобиться преобразовать счетчик во время и дату и обратно, предлагаю вот это решение
Хочу напомнить, что вы не пуп земли, и STM не крутится вокруг вас и ваших хотелок. И если что-то не нравится конкретно вам, то это не значит, что это что-то говно в первой инстанции. Из ошибок отмечу ключевые слова ассемблер, умножение, страница. На лицо явное не знание принципов создания архитектуры, отсюда и желание впихнуть куда попало.
Простите. Вы же наверника пишите с самодельного ПК на святом АВР, и не имеете возможность погуглить характеристики благословляемого и обсираемогово вами устройства. Скажу лишь, что вы зря боготворите часовые кварцы. Имеющиеся в шаговой доступности обладают гораздо худшими харрактеристиками, чем высокочастотные. А конденсаторик покрутить, можно и на высокочастотном. Понимаю, такие детали вам неизвестны, вы же на ПК с авр сидите.
Насколько я помню, _YS_ не так давно делился опытом о том, что часики на МК у него на часовом кварце куда точнее ходят, чем на ВЧ. С чем связано не знаешь?
С тем, что кварцы на одну и туже частоту бывают разной точности. Читай внимательно мой пост, я тоже делюсь опытом. У палки два конца.
Там ты говорил о том, что кварцы «в шаговой доступности» имеют куда худшую точность, чем ВЧ. А _YS_, что характерно, берет детали именно в шаговой доступности.
Я понимаю, что _YS_ эталон, божество и прочее, а остальных радиолюбителей для вас не существует. Вы вообще в курсе, что страна у нас большая?
Воу, воу! Здравствуйте! :D
Именно после этого комментария я тоже решил вступить в холивар. :D Эталон прибыл для прояснения ситуации! :D
Да будет вам известно, что «часовые» и «обычные» кварцы сильно различаются.
Вкратце, у «часового» и «обычного» кварца разная физическая конструкция и разный тип среза кристалла (для первого — XY и камертон, для второго — AT и, чаще всего, пластина/диск).
Часовые кварцы безусловно стабильнее при условии верного включения. А они имеют особенности включения; прежде всего, надо иметь в виду, что предельная рассеиваемая мощность для них гораздо ниже, чем для «обычных», и потому про нее надо думать и, при необходимости, ограничивать.
Такие дела.
Именно после этого комментария я тоже решил вступить в холивар. :D Эталон прибыл для прояснения ситуации! :D
Да будет вам известно, что «часовые» и «обычные» кварцы сильно различаются.
Вкратце, у «часового» и «обычного» кварца разная физическая конструкция и разный тип среза кристалла (для первого — XY и камертон, для второго — AT и, чаще всего, пластина/диск).
Часовые кварцы безусловно стабильнее при условии верного включения. А они имеют особенности включения; прежде всего, надо иметь в виду, что предельная рассеиваемая мощность для них гораздо ниже, чем для «обычных», и потому про нее надо думать и, при необходимости, ограничивать.
Такие дела.
Ты не в тот блог публикуешь. Этот — для всякой теории вида «как посчитать резистор». Твое… Гм. По большей части текст представляет просто комментарий к программе, был бы блог «ассемблер» — туда ему и было бы самое место. А так — вероятно, в «AVR».
Вместо этого можно было завести табличку, хранящую для каждого разряда/сегмента адрес регистра и номер бита, и проходить ее в цикле. Редактирование распиновки сразу резко облегчается и резко снижается вероятность ошибки, а код избавляется от копипасты.
Алсо, судя по карте регистров — свободных регистров предостаточно, вместо сохранения регистра TEMP можно было просто выделить прерыванию OVF2 свой личный рабочий регистр.
Да и применение ATmega328 мне показалось неоправданно жирным.Полагаю, этот скетч прекрасно влезет в ATMEGA8A, надо только выбрать другой таргет в IDE. Конечно, переделать его под, скажем, другой индикатор без знания С (и немного С++) не выйдет.
не более 64536 импульсовУ тебя опечатка. Алсо, 65535. На 65536-м произойдет переполнение. Аналогично с 16-разрядным, на 16777216-м импульсе счетчик насчитает ноль.
;------ Конфигурация портов ----------------------------------------------------;При изменении раскладки пинов эту часть придется искать в коде и изменять. И еще процедуры вывода на дисплей перелопачивать, внимательно правя там порты.
OUTI DDRB, (1<<SegG)|(1<<SegH)|(1<<Rat1)
Вместо этого можно было завести табличку, хранящую для каждого разряда/сегмента адрес регистра и номер бита, и проходить ее в цикле. Редактирование распиновки сразу резко облегчается и резко снижается вероятность ошибки, а код избавляется от копипасты.
AVR не имеет приоритетности прерыванийНасколько я помню, таки имеет. Просто приоритеты нельзя изменить, а так — прерывание OVF1 приоритетнее, чем OVF0, OVF2 — вообще самое приоритетное из использованных.
Алсо, судя по карте регистров — свободных регистров предостаточно, вместо сохранения регистра TEMP можно было просто выделить прерыванию OVF2 свой личный рабочий регистр.
Из-за особеностей флагового автомата подпрограммы не оформлены как подпрограммы, нет обращения по метке, нет вызовов RCALL и RET в концеНа самом деле, никто не мешает для улучшения читаемости выделить подпрограммы в полноценные подпрограммы. Тогда в цикле останется только
loop:
SBRC FLAGS, Flg1
RCALL Proc1
SBRC FLAGS, Flg2
RCALL Proc2
SBRC FLAGS, Flg3
RCALL Proc3
RCALL RefrDisp
RJMP loop
Если ты про размер, то умелое применение подхода таблицы данных + циклы способно его уменьшить, и порой весьма заметно.
Думаю, речь о чистоте (отсутствии лишних телодвижений, мусорного кода, дурного выхлопа компилятора).
Техническое изделие может иметь множество уровней представления. Верхний — алгоритм работы устройства, который видит пользователь, затем код, который реализует этот алгоритм, затем командочки которые выполняются на процессоре, в которые выливается этот код и т.д. Тебя волнует только код, а большинству вообще кроме верха нафиг ничего не надо. Инженер же смотрит на весь пирог в целом, чтобы все уровни были без дурных излишеств, а не только избранные. Сущности каждого уровня должны логично и просто, без лишних фендибоберов переходить в сущности нижележащего… Потому что для чистоты реализации она должна быть во всех уровнях, иначе её не будет ни в одном. Именно на этом и построен Си, кстати… Любители же чистого кода никогда никакого чистого кода не получат. Потому что заметание мусора под ковёр не равно чистоте.
Потому что для чистоты реализации она должна быть во всех уровнях, иначе её не будет ни в одном.Тобишь чистоты ты не получишь вообще, потому что на гейт-левеле микроконтроллер сгенерен HDL-синтезатором. Который дает знатную кашку.
Кроме того, если ты не заметил — я не предлагаю сменить уровень абстракции. Я комментирую сделанное на текущем.
Потому что заметание мусора под ковёр не равно чистоте.Если ты говоришь о компиляторах и ЯВУ, то это не заметание мусора под ковер, а перекладывание работы на кремниевые мозги. Они быстрее и не ошибаются. Хотя и не всегда делают лучшим образом, но мы работаем над этим (с). Да и в большинстве случаев качество их работы достаточно.
Если ты говоришь о компиляторах и ЯВУДаже не столько о них, сколько о дури, которую привносят сами разработчики. Типа хранения времени в формате RTC. Геморно на аппаратном уровне (дикой сложности блок, который реализует календарь), дико геморно в программе (сравнить два времени). И всё потому что какой-то идиот решил что раз время в формате RTC удобно выводить, значит в нём и хранить будем. Типичный пример перекладывания «лишней работы» на железо, в итоге всегда мусор на одном уровне зеркально переходит в мусор на остальных…
(дикой сложности блок, который реализует календарьНе такой уж и дикой, просто несколько счетчиков малой разрядности плюс логика задания числа дней в месяце, достаточно простая.
дико геморно в программе (сравнить два времени)Сравнение — не единственная, и в эмбеде вероятно даже не основная операция с временем. К тому же, сравнить структурки со временем проще, чем декодировать юникс-тайм в нечто пригодное для вывода на индикатор.
>> умелое применение подхода таблицы данных +
Я не против, наверное просто не умею. Да с заменой пинов есть проблемма, но дело не в моих руках, дело в препроцессоре ассемблера. Не забывайте, вы не в С.
Я не против, наверное просто не умею. Да с заменой пинов есть проблемма, но дело не в моих руках, дело в препроцессоре ассемблера. Не забывайте, вы не в С.
Вот с этим не поспорить. Не ругайте пианиста, он играет как умеет…
А как лучше покажите чем что заменить. Иначе это просто болтовня.
А как лучше покажите чем что заменить. Иначе это просто болтовня.
Не ругайте пианиста, он играет как умеет…Э нет. Так не пойдет. Если пианиста не ругать, он так и будет играть как умеет, а не улучшаться.
Иначе это просто болтовня.Это не болтовня. Это критика. И я подсказываю, в каком направлении копать. Снова писать за тебя процедуру перемешивания бит в 30 байтах флеша мне на данный момент лень.
Я то понадеялся, что второй раз вы не лоханетесь. Приведу заключительный текст из той статьи:
Я сразу, как поглядел на адресацию индикаторов с ОА, понял что это гиблое дело, даже проверочный код не стал писАть. Некоторым это показалось неочевидно. Развязался флейм, для проверки своего предположения я попросил VGA предоставить проверочный код. Код на ассемблере MCS-51 был предоставлен. Приведу результаты тестирования, вырезка, орфография сохранена:
… Тут предоставленный код на MCS-51…
Итого, 1169 — 31 = 1138 команд потрачено на дебильную адресацию…
Это называется написать за меня код?
Я сразу, как поглядел на адресацию индикаторов с ОА, понял что это гиблое дело, даже проверочный код не стал писАть. Некоторым это показалось неочевидно. Развязался флейм, для проверки своего предположения я попросил VGA предоставить проверочный код. Код на ассемблере MCS-51 был предоставлен. Приведу результаты тестирования, вырезка, орфография сохранена:
… Тут предоставленный код на MCS-51…
Итого, 1169 — 31 = 1138 команд потрачено на дебильную адресацию…
Это называется написать за меня код?
Команд потрачено 21 штука. Времени исполнения — да, 1к тактов, но даже если ты именно это и подразумевал изначально — из текста оно ни разу не очевидно. Однако, если глянуть на первый же твой коммент, то станет ясно, что место таки идет о занимаемом во флеше месте. Иначе ты бы сразу сказал, что да — код будет коротким, но займет много времени.
К тому же, если команд доступно всего 4096 на каком-нить ATMEGA8, то тактов там доступно 16000000 каждую секунду, что делает цену в 1к тактов несущественной для реальных условий.
К тому же, если команд доступно всего 4096 на каком-нить ATMEGA8, то тактов там доступно 16000000 каждую секунду, что делает цену в 1к тактов несущественной для реальных условий.
Я это и имел в виду. Главный цикл на то и главный цикл, чтобы в нем крутились задачи, которые не требуется уминать в микросекунды.
Хотя на AT89C2051 действительно можно впороться в ситуацию, когда вывод в такой дисплей будет жрать 10-20% процессорного времени, и процентов 20-50 из них будет уходить на перемешивание битиков, но надо еще найти задачу, где это вообще будет проблемой.
Хотя на AT89C2051 действительно можно впороться в ситуацию, когда вывод в такой дисплей будет жрать 10-20% процессорного времени, и процентов 20-50 из них будет уходить на перемешивание битиков, но надо еще найти задачу, где это вообще будет проблемой.
СцепилисьВ кои веки здеся опять наконец появился Лайфловер, но этот бездарный киндервуд, зануда и буквоед опять вцепился в него. Что он хочет доказать этим? То что он вумнее или лучше? И так ясно, что, как разработчик и пейсатель интересных технических статей — он полный нуль. А потом опять начнет ныть: Вот де, люди ничего уже здеся не пишут и даже не ходютъ сюды!
- well-man2000
- 23 декабря 2017, 23:24
- ↑
- ↓
В дешевых OEM GPS модулях обычно ставят TCXO — термокомпенсированный генератор. Его точность и стабильность выше на порядок «обычного» кварцевого генератора (ну, генератора на инверторе и кварце из магазина за 50 р, к примеру) и составляет порядка 1e-6. Но если навигационное решение приемником найдено, то точность установки фронта секундной метки PPS составит уже 40 — 100 нС, то есть еще повысится на один-два порядка. Если же хочется иметь такую точность и стабильность генератора сразу из коробки — то пригодны только OCXO (oven-controlled, термостатированные) генераторы, но стоят эти фиговины уже откровенно дорого, большие по габаритам ну и продаются не на каждом углу.
В дешевых OEM GPS модулях обычно ставят TCXO — термокомпенсированный генератор. Его точность и стабильность выше на порядок «обычного» кварцевого генератораЛогично, в принципе, но дешевле его и поставить, если сам GPS не нужен)
то точность установки фронта секундной метки PPS составит уже 40 — 100 нС, то есть еще повысится на один-два порядкаКак я понимаю, это абсолютная точность клока относительно часов на спутниках. Но период сигнала по прежнему будет определяться TCXO с погрешностью порядка 10^-6, не? Вот на большом отрезке времени, за счет регулярных синхронизаций со спутником можно получить точность порядка точности часов на спутнике.
то пригодны только OCXO (oven-controlled, термостатированные) генераторыБывают же еще атомные, где-то на кикстартере был проект карманных (или даже наручных ли) часов на таком :)
Вот цитата из даташита на приемник GEOS-3: «Секундная метка времени формируется с временным дискретом 61нс (определяется
частотой опорного генератора 16,369МГц)». То есть, дискретность привязки времни зависит от внутреннего генератора, но точность зависит только от наличия навигационного решения, большой интервал времени для получения этой точности не нужен. Появилась буква «A» в NMEA — все, PPS приколочен к UTC с точностью +-61 нс.
Вот еще цитата из даташита на EB-600: «The 1PPS signal accuracy directly relates to the position accuracy. The GPS /
Glonass signals travel at the speed of light, therefore a position inaccuracy directly
translates into 1PPS inaccuracies.
10 m position deviation ≈ 33 ns 1PPS deviation (typically)
100 m position deviation ≈ 333 ns 1PPS deviation (typically)»
Ну, атомные часы бывают, да. Но это уже фантастиш, я про такое и писать не стал :) Они-то и стоят на спутниках, собственно. Бывают атомные часы и в наземных приемниках — с такими топографы бегают иногда. С наземной базой точность определения координат в радиусе действия базы (5 — 10 км) — единицы миллиметров.
частотой опорного генератора 16,369МГц)». То есть, дискретность привязки времни зависит от внутреннего генератора, но точность зависит только от наличия навигационного решения, большой интервал времени для получения этой точности не нужен. Появилась буква «A» в NMEA — все, PPS приколочен к UTC с точностью +-61 нс.
Вот еще цитата из даташита на EB-600: «The 1PPS signal accuracy directly relates to the position accuracy. The GPS /
Glonass signals travel at the speed of light, therefore a position inaccuracy directly
translates into 1PPS inaccuracies.
10 m position deviation ≈ 33 ns 1PPS deviation (typically)
100 m position deviation ≈ 333 ns 1PPS deviation (typically)»
Ну, атомные часы бывают, да. Но это уже фантастиш, я про такое и писать не стал :) Они-то и стоят на спутниках, собственно. Бывают атомные часы и в наземных приемниках — с такими топографы бегают иногда. С наземной базой точность определения координат в радиусе действия базы (5 — 10 км) — единицы миллиметров.
Появилась буква «A» в NMEA — все, PPS приколочен к UTC с точностью +-61 нс.Вот именно, приколочен к UTC. Если только оно не приколачивает каждую метку к сигналу со спутника — то период меток на малом отрезке времени (между моментами синхронизации) будет определяться стабильностью тактового генератора модуля. А для частотомера он и нужен.
Но это уже фантастиш, я про такое и писать не стал :)Ну, как я понял из прооекта тех часов — если тебя не смущает заплатить несколько сотен (или тысяч ли) баксов, то атомный клок вполне доступен и даже имеет разумные размеры (со спичечный коробок).
Если только оно не приколачивает каждую метку к сигналу со спутника — то период меток на малом отрезке времени (между моментами синхронизации) будет определяться стабильностью тактового генератора модуля.Да, все так. Нет навигационного решения — точность частоты секундной метки такая, какую может обеспечить TCXO сам по себе. Разве это не очевидно?
если тебя не смущает заплатить несколько сотен (или тысяч ли) баксов, то атомный клок вполне доступен и даже имеет разумные размеры (со спичечный коробок)Поинтересовался сейчас и обнаружил, что китайцы пихают Б/У за относительно приемлемые деньги :) goo.gl/UYpwgH
Нет навигационного решения — точность частоты секундной метки такая, какую может обеспечить TCXO сам по себе.Вот и возникает вопрос — как часто оно синхронизирует эту метку? Если синхронизируется каждая метка, то да — точность там будет порядка 61нс плюс точность часов на спутнике.
Поинтересовался сейчас и обнаружил, что китайцы пихают Б/У за относительно приемлемые деньги :) goo.gl/UYpwgHВо, с таким можно клепать частотомер на 10 знаков!)
Вот и возникает вопрос — как часто оно синхронизирует эту метку? Если синхронизируется каждая метка, то да — точность там будет порядка 61нс плюс точность часов на спутнике.Да, синхронизируется каждая PPS. Логика тут простая: есть решение — метка синхронизирована. Предвосхищая следующий вопрос, как оно там это происходит в подробностях, я отвечу: я не знаю :) Про то в даташитах не пишут. Разработкой самих навигационных приемников я никогда не занимался.
Логика тут простая: есть решение — метка синхронизирована.Это логично, потому что решение выдает 4 переменные — текущее время и координаты. Но для синхронизации каждого PPS нужно считать решение каждую же секунду, а какой там update rate у приемников — я не знаю, не знаю и какой он вообще максимально возможен в теории.
а какой там update rate у приемниковУ большинства приемников — 1 раз в секунду, но у каких-то можно нарулить и более частый апдейт.
Жаль, что приемники тактируются генераторами на всякие хитрые частоты. Вот, скажем, OCXO на 10 МГц почему-то является самым распространенным, часто продается относительно недорого на всяких аукционах и т.д. Мне всегда было интересно, что произойдет, если дешевой джипиэсине заменить генератор на вариант покруче. Что произойдет с точностью определения координат, если стабильность и точность генератора увеличить на два порядка? :)
Решение навигационным приемником вычисляется непрерывно, а выдается дискретно. Каждая метка времени (1 PPS) синхронизирована либо с системным временем навигационной системы, либо со шкалами UTC(SU), UTC(US) в зависимости от настроек приемника. Погрешность синхронизации со шкалами времени может быть различна и доходить до сотен наносекунд, а при использовании длинных антенных кабелей и до единиц микросекунд, однако изменение этой погрешности синхронизации во много раз меньше и составляет несколько (десятков) наносекунд. Таким образом периоды сигнала 1 PPS могут отличаться друг от друга на эти несколько (десятков) наносекунд и это различие будет не систематической, а случайной величиной, с которой, до некоторой степени, можно бороться усреднениями.
10 МГц является стандартом опорной частоты в измерительной технике. В СССР также использовались частоты 5 МГц и совсем редко 1 МГц. Чем выше частота, тем меньше времени необходимо для её измерения с той же точностью.
Но вряд ли радиолюбительские конструкции на микроконтроллерах по точности упрутся в точность 1 PPS GPS/GLONAS. Ведь основной проблемой является подсчет периодов измеряемой частоты, а ведь их никогда не бывает целого количества.
10 МГц является стандартом опорной частоты в измерительной технике. В СССР также использовались частоты 5 МГц и совсем редко 1 МГц. Чем выше частота, тем меньше времени необходимо для её измерения с той же точностью.
Но вряд ли радиолюбительские конструкции на микроконтроллерах по точности упрутся в точность 1 PPS GPS/GLONAS. Ведь основной проблемой является подсчет периодов измеряемой частоты, а ведь их никогда не бывает целого количества.
>> Ведь основной проблемой является подсчет периодов измеряемой частоты, а ведь их никогда не бывает целого количества.
Это проблема давно решена.
В частотомерах комбинированного счета (извините, не знаю как правильнее назвать).
Это когда одновременно подсчитываются как измеряемая частота так и опорная.
При этом отсчет начинается от синхронизатора измеряемой.
Такой метод гораздо точнее, тем более если опорная выше или соизмерима с измеряемой.
Это проблема давно решена.
В частотомерах комбинированного счета (извините, не знаю как правильнее назвать).
Это когда одновременно подсчитываются как измеряемая частота так и опорная.
При этом отсчет начинается от синхронизатора измеряемой.
Такой метод гораздо точнее, тем более если опорная выше или соизмерима с измеряемой.
Поясните, пожалуйста, как этот помогает посчитать части периодов? Ведь фронты измеряемой и опорной частоты несинхронны и всегда возникает дополнительная погрешность из-за этой несинхронности. А методов есть много и разных, только речь шла от том, что на микроконтроллерах в точность опорной частоты GPS/GLONASS приемника не упереться.
Тот частотомер — просто детская игрушка, не более, и про PLL там ни слова. Годен только в качестве «быстрого старта», как собственно и ваша конструкция. Измерение частоты с помощью «временных ворот» — это самый начальный этап. Далее за ним я бы поставил преобразование Фурье с дополнением нулями, ФАПЧ и преобразование Уолша.
Ну, а для всего этого прежде всего нужен эталон частоты — вот и зашла о нем речь, а GPS — просто самый дешевый способ такой эталон получить в бытовых условиях вот и зашла о нем речь. Мы все здесь учимся друг у друга ну и выпендриваемся помаленьку :) Разве это плохо?
А к вопросу, зачем мерять частоту точнее пары герц я отвечу — каждую физическую величину можно так или иначе измерить с помощью другой физической величины или величин. Например, представьте себе, что вы задумали сделать точный широкодиапазонный L/C измеритель на основе измерения частоты.
Ну, а для всего этого прежде всего нужен эталон частоты — вот и зашла о нем речь, а GPS — просто самый дешевый способ такой эталон получить в бытовых условиях вот и зашла о нем речь. Мы все здесь учимся друг у друга ну и выпендриваемся помаленьку :) Разве это плохо?
А к вопросу, зачем мерять частоту точнее пары герц я отвечу — каждую физическую величину можно так или иначе измерить с помощью другой физической величины или величин. Например, представьте себе, что вы задумали сделать точный широкодиапазонный L/C измеритель на основе измерения частоты.
Да в общем-то любую книжку по спектральному анализу. С Фурье и нулями там основная идея в том, что нужно определить частоту, соответствующую максимуму в спектре. Для этого нужно сначала это преобразование сделать. Обычно для этого пользуются алгоритмом БПФ, но, хотя он и быстро работает, у него есть недостаток — шаг по частоте в вычисленном спектре равен Fs/2^n, то есть, если частота дискретизации высокая или элементов в массиве мало — шаг получится большим и нужной точности можно и не достичь. А искусственно дополнив массив нулями это ограничение можно преодолеть. При этом спектр станет более «размазанным», но максимум у него останется на своем месте.
Еще Фурье можно считать не по БПФ, а так, как оно дается по-определению. Тут спектр вычисляется в любой произвольной точке, но появляется проблема поиска максимума в широкой области. Этот метод годен для подсечения небольших отклонений частоты — работает быстрее и точнее БПФ. Для поиска максимума с заданной точностью его можно совместить с методом деления отрезка пополам или подобным.
Еще Фурье можно считать не по БПФ, а так, как оно дается по-определению. Тут спектр вычисляется в любой произвольной точке, но появляется проблема поиска максимума в широкой области. Этот метод годен для подсечения небольших отклонений частоты — работает быстрее и точнее БПФ. Для поиска максимума с заданной точностью его можно совместить с методом деления отрезка пополам или подобным.
Я когда то исследовал вопрос с точностью PPS сигнала у разных приемников штудированием даташитов. Нашел что точность фронта определяется в основном частотой опорного генератора. Однако было насколько приемников, которые в качестве решения выдавали также точное временное значение PPS пульса. То есть узнать время фронта PPS можно с более высокой точностью, чем позволяет тактовый генератор, однако само время фронта так же определяется частотой опоры.
Читал что разрешение по пространству может быть достигнуто порядка 3см. Можно соответствующее разрешение ожидать и по временным меткам, то есть разницу между 2 импульсами PPS знать с соотв точностью.
Читал что разрешение по пространству может быть достигнуто порядка 3см. Можно соответствующее разрешение ожидать и по временным меткам, то есть разницу между 2 импульсами PPS знать с соотв точностью.
Это все равно что рассуждать на какую долу миллиметра ошибается ваша линейка. Да какая практическая разница?А разница простая, залезет вот эта штука в ту дырку или нет? А если залезет, то с натягом или зазором?
Смотря что и как использовать. Если генератором в качестве подмотки спидометра пользоваться, то шкала вообще не нужна
Вспомнил, на мои слова «Т.к. шестнадцатиразрядный счетчик может вместить не более 64536 импульсов» вы оветили «У тебя опечатка. Алсо, 65535. На 65536-м произойдет переполнение. Аналогично с 16-разрядным, на 16777216-м импульсе счетчик насчитает ноль.»
Вы знаете математика с вами не согласна, значение 2 в 16-й степени будет 65536, можете проверить на калькуляторе. Вашу ошибку я заметил, поправлять не стал, зачем холивар начинать?
А знать табличку кодов ассемблера, и уметь грамотно применять язык ассемблер это совсем разные вещи.
Вы знаете математика с вами не согласна, значение 2 в 16-й степени будет 65536, можете проверить на калькуляторе. Вашу ошибку я заметил, поправлять не стал, зачем холивар начинать?
А знать табличку кодов ассемблера, и уметь грамотно применять язык ассемблер это совсем разные вещи.
Вы знаете математика с вами не согласна, значение 2 в 16-й степени будет 65536, можете проверить на калькуляторе.Разумеется 65536. Вот только в 16-битный регистр влезет 2^16-1, то есть 65535.
А у тебя, напомню, вообще написано 64536.
А знать табличку кодов ассемблера, и уметь грамотно применять язык ассемблер это совсем разные вещи.Почему-то люди, знающие только ассемблер, уверены, что это сакральное знание, которое другим не под силу. При этом сами ничего из разряда «вау, я бы не додумался!» не демонстрируют, совершенно типичный и прямолинейный код на ассемблере.
В отличие от сишников вроде Кармака, чей «быстрый обратный корень» до сих пор вызывает отвал челюсти у всех, кто его видит впервые.
Первая описка, не ошибка, мог бы сразу сказать, бывает, поправил.
А вот 2^16 даже в двоичном счетчике 65535, не надо забывать что ноль хотя и фантомное число, на емкость счетчика влияет непосредственно.
Ассемблер для меня отдушина, на работе я иногда программирую PLC Siemens, иногда пишу на Delphi под Windows конфигурационные программы под конкретное оборудование. Очень редко конфигурирую программы Brewmaxx(ProLiiT). Ассемблер для меня отдушина от всего этого безобразия.
А вот 2^16 даже в двоичном счетчике 65535, не надо забывать что ноль хотя и фантомное число, на емкость счетчика влияет непосредственно.
Ассемблер для меня отдушина, на работе я иногда программирую PLC Siemens, иногда пишу на Delphi под Windows конфигурационные программы под конкретное оборудование. Очень редко конфигурирую программы Brewmaxx(ProLiiT). Ассемблер для меня отдушина от всего этого безобразия.
Первая описка, не ошибка, мог бы сразу сказать, бывает, поправил.Я об этом написал в первом же своем комментарии.
не надо забывать что ноль хотя и фантомное число, на емкость счетчика влияет непосредственноВот именно об этом я и не забываю, в отличие от тебя. В счетчике есть место для нуля импульсов, поэтому 65536 импульсов туда не влезет.
Ассемблер для меня отдушинаРад за тебя. Но это ни разу не означает, что ассемблер я знаю хуже тебя.
Комментарии (180)
RSS свернуть / развернуть