Как сделать индикатор в 1с

Добавил пользователь Skiper
Обновлено: 05.10.2024

Изначально искал, как сделать индикатор процесса в управляемых формах. Почти все ссылки с интернета идут на этот сайт, в результате понял что индикатор делается через функцию Сообщить().
Но тут задумался, а чего бы не сделать чтоб в таблице на форме в одной колонке можно было вывести индикатор для каждой строки?
оказалось не так и сложно, больше времени ушло на прорисовку графического индикатора для каждого процента (итого 100 картинок)
Дальше встал вопрос как их вместить в обработку и как вызывать?
в результате получилась вот такая вот обработка, которая содержит в себе кучу примеров работы в управляемых формах, а именно:
1. вывод картики в ячейки табличной части через навигационную ссылку
2. обращение к макету и вытаскивание из него картинок
3. создание навигационных ссылок для внешних графических файлов, и подсовование их "на лету" в форму

Перед октытием читаем картинки из макета и формируем на их основе навигационные ссылки, которые помещаем в список значений. (в дальнейшем булем обращатся к нему из расчета индекс в списке значений = текущий процент.

при обработке результата определяем процент и вызываем ссылку из списка значений

надеюсь кому то пригодится, по мне так очень красиво получается если использовать в обработках обмена :)

на втором рисунке показано как это выглятит если на боевую обработку выгрузки применить, а скриншот самой обработки на первом рисунке.

Рейтинг: 225

В статье дано описание создания индикатора на форме в среде разработки 1С:Предприятие 7.7 исключительно типовыми средствами.

Многим программистам прихходится сталкиваться с проблемой индикациии прогресса выполнения длительных процессов в 1С:Предприятии 7.7.

Каждый решает этот вопрос по-своему, ниже будет описание моего решения проблемы.

Индикатор на форме отображается с помощью элементов: рамка группы, текст. В элемент текст выводятся символы "|".

Скриншот

Как выводить символы, индицирующие процесс?

Рассмотрим пример. Пускай символов, индицирующих процесс, будет 3, а всего значение 7.

Помните, как раньше на платформе 1С:Предприятие 8.2 приходилось кропотливо описывать дружелюбный интерфейс пользователя с подсказками и пояснениями!? Как плодились группы элементов, декорации и прочие украшения, лишь бы форма выглядела пристойно!?

Начиная с релиза 8.3.1 платформы 1С:Предприятие 8.3 все изменилось: для элементов управления появилась расширенная подсказка, а мир засиял новыми красками).

Одним из улучшений, которые облегчают жизнь разработчику и повышают лояльность пользователей, стала расширенная подсказка для элементов:

  • поле ввода
  • таблица
  • группа
  • кнопка
  • декорация (текст)

В палитре свойств, кроме самой подсказки появилось два дополнительных поля:

  • Отображение подсказки, которое управляет способом представления подсказки пользователю;
  • Подсказка ввода, которая отображается непосредственно в пустом поле ввода;

Подсказка ввода

Атрибуты расширенной подсказки в палитре свойств

Давайте посмотрим, как видит эти подсказки пользователь:

Пример использования расширенной подсказки на платформе 1С:Предприятие 8.3

Есть и другие способы отображения подсказки:

  • Авто — автоматический режим (показывается обычная всплывающая подсказка);
  • Нет — подсказка не показывается;
  • Всплывающая — подсказка показывается во всплывающем окне (всем до боли знакомая, стандартная подсказка);
  • Кнопка — подсказка показывается в отдельном окне после нажатия кнопки (см. на рисунке выше);
  • Отображение сверху, справа, снизу и т.п. — подсказка выводится в виде текста сверху, справа, снизу и т.п. от элемента управления;

Расширенная подсказка

И это еще не все. Разработчик может задать собственную подсказку с цветным оформлением и гиперссылками. Для этого нужно включить для элемента управления режим отображения расширенной подсказки:

Включение режима отображения расширенной подсказки

Для отображения цифровой информации в системах на базе микроконтроллеров используются светодиодные семисегментные индикаторы. Они просты в управлении, имеет высокую яркость, широкий диапазон рабочих температур и низкую стоимость. К недостаткам светодиодных индикаторов относятся – высокое энергопотребление, отсутствие управляющего контроллера и скудные возможности по выводу буквенной информации.
Светодиодный семисегментный индикатор представляет собой группу светодиодов расположенных в определенном порядке и объединенных конструктивно. Зажигая одновременно несколько светодиодов можно формировать на индикаторе символы цифр. Индикаторы различаются по типу соединения светодиодов – общий анод, общий катод, по количеству отображаемых разрядов – однораразрядные, двух разрядные и т.д. и по цвету – красные, зеленые, желтые и т.д.


Семисегментным индикатором можно управлять статически или динамически. При статическом управлении разряды индикатора подключены к микроконтроллеру независимо друг от друга и информация на них выводится постоянно. Этот способ управления проще динамического, но без использования дополнительных элементов, как-то сдвиговые регистры, подключить многоразрядный семисегментный индикатор к микроконтроллеру будет проблематично - может не хватить выводов.


Динамическое управление (динамическая индикация) подразумевает поочередное зажигание разрядов индикатора с частотой, не воспринимаемой человеческим глазом. Схема подключения индикатора в этом случае на порядок экономичнее благодаря тому, что одинаковые сегменты разрядов индикатора объединены.


Рассмотрим простейший случай управления индикатором – вывод одной цифры. Схема для наших экспериментов приведена ниже.


Чтобы зажечь на индикаторе какую-то цифру нужно настроить порты, к которым подключен индикатор, в режим выхода, “открыть” транзистор (в данном случае подать на базу “единицу”) и установить в порту микроконтроллера её код.
В зависимости от того, куда подключены сегменты индикатора – коды могут быть разные. Для нашего случая коды цифр будут выглядеть так.

unsigned char number[] =
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f //9
>;

Используя десятичные цифры от 0 до 9 в качестве индекса массива, легко выводить в порт нужные коды.

unsigned char number[] =
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f //9
>;

unsigned char count = 0;
int main( void )
//порт, к которому подкл. сегменты
PORTB = 0xff;
DDRB = 0xff;

//вывод, к которому подкл. катод
PORTD |= (1 while (1) PORTB = number[count];
count++;
if (count == 10) count = 0;
__delay_cycles (8000000);
>
return 0;
>
Эта программа каждую секунду выводит значение переменной count на семисегментный индикатор. Индикация в данном случае - статическая.

Идем дальше – вывод двух цифр. Настройка портов и коды цифр остаются без изменений, но теперь нам нужно добавить кусок кода, который будет зажигать разряды индикатора по очереди. Частота смены разрядов должна быть достаточно высокой, чтобы свечение индикатора воспринималось без мерцания.

unsigned char number[] =
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f //9
>;

unsigned char count = 0;

//числа для вывода на индикатор
unsigned char data1 = 2;
unsigned char data2 = 5;

int main( void )
//порт, к которому подкл. сегменты
PORTB = 0xff;
DDRB = 0xff;

//порт, к которому подкл. катод
PORTD = 0;
DDRD = (1 while (1)

//гасим оба разряда
PORTD &= ~((1 //выводим в порт код цифры
//и зажигаем следующий разряд
if (count == 0) PORTB = number[data2];
PORTD |= (1 if (count == 1) PORTB = number[data1];
PORTD |= (1 if (count == 2) count = 0;

//частота смены разрядов будет 100 Гц при кварце 8МГц
__delay_cycles (800000);
>
return 0;
>
Эта программа просто выводит любое поразрядно заданное число от 0 до 99.
Частота смены разрядов семисегментного индикатора задается с помощью программной задержки __delay_cycles(). Это не самое удачное решение, потому что добавление каких-нибудь других задач в цикл while будет мешать выводу на индикатор. Давайте организуем смену разрядов индикатора с помощью аппаратного таймера/счетчика Т0

unsigned char number[] =
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f //9
>;

//числа для вывода на индикатор
volatile unsigned char data1 = 0;
volatile unsigned char data2 = 0;

int main( void )
//порт, к которому подкл. сегменты
PORTB = 0xff;
DDRB = 0xff;

//порт, к которому подкл. катод
PORTD = 0;
DDRD |= (1 //инициализация таймера Т0
//частота прерываний 100Гц при кварце 8МГц
TIMSK = (1 __enable_interrupt ();
while (1) //программный счетчик секунд
data1++;
if (data1 == 10) data1 = 0;
data2++;
if (data2 == 10) data2 = 0;
>
__delay_cycles (8000000);
>
return 0;
>

//гасим оба разряда
PORTD &= ~((1 //выводим в порт код цифры
//и зажигаем следующий разряд
if (count == 0) PORTB = number[data2];
PORTD |= (1 if (count == 1) PORTB = number[data1];
PORTD |= (1 if (count == 2) count = 0;
>
Переменные data1, data2 объявлены с ключевым словом volatile, потому что они используются и в основном коде и в прерывании. В проекте под GCC я забыл поставить его поставить, и компилятор выкинул обе переменные, посчитав их ненужными!

Прерывания таймера происходят параллельно выполнению цикла while. Это позволяет выполнять в цикле какую-нибудь полезную задачу. В данном примере с помощью двух переменных в цикле организован программный счетчик от 0 до 99.
Использовать две восьмиразрядные переменные для организации счетчика от 0 до 99 неудобно и расточительно, ведь такой счетчик можно сделать и на одной переменной типа unsigned char. Хорошо, счетчик мы сделаем, а как вывести его значение на семисегментный индикатор? Нужен код “разбивающий” десятичное число на отдельные разряды и вот как он выглядит:

//программный счетчик
unsigned char counterProg = 35;

//”разбиваем” значение счетчика на отдельные разряды
data1 = counterProg % 10;
data2 = counterProg/10;

data1 = counterProg % 10 – это операция деления по модулю 10 (деление с остатком). Результатом этого выражения будет остаток от деления переменной counterProg на 10, то есть для нашего случая 5.

counterProg/10 – это целочисленное деление на 10. Результатом этого выражения будет число 3.

Таким образом, в переменные data2, data1 будут записаны числа 3 и 5 соответственно, значение счетчика counterProg при этом не изменится.

unsigned char number[] =
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f //9
>;

//числа для вывода на индикатор
volatile unsigned char data1 = 0;
volatile unsigned char data2 = 0;

//программный счетчик секунд
unsigned char counterProg = 0;

int main( void )
//порт, к которому подкл. сегменты
PORTB = 0xff;
DDRB = 0xff;

//порт, к которому подкл. катод
PORTD = 0;
DDRD |= (1 //инициализация таймера Т0
TIMSK = (1 __enable_interrupt ();
while (1) //программный счетчик секунд
counterProg++;
if (counterProg == 100) counterProg = 0;
data1 = counterProg % 10;
data2 = counterProg/10;
__delay_cycles (8000000);
>
return 0;
>

//гасим оба разряда
PORTD &= ~((1 //выводим код цифры в порт
//и зажигаем следующий разряд
if (count == 0) PORTB = number[data2];
PORTD |= (1 if (count == 1) PORTB = number[data1];
PORTD |= (1 if (count == 2) count = 0;
>
Следующий этап работы над программой – выделение кода обслуживающего светодиодный семисегментный индикатор в отдельные функции. Какой минимальный набор функций нам необходим? Функция инициализации, функция вывода на индикатор и функция преобразования чисел и записи их в буфер.

Функция инициализации

volatile unsigned char data[2];

void IND_Init( void )
//порт к которому подкл. сегменты
PORT_IND = 0xff;
DDR_IND = 0xff;

void IND_Conv( unsigned char value)
unsigned char tmp;
tmp = value % 10;
data[0] = number[tmp];
tmp = value/10;
data[1] = number[tmp];
>

Процедура преобразования чисел аналогична описанной выше. Единственное отличие – в буфере (data[]) мы теперь сохраняем не результат преобразования, а коды цифр. Зачем делать в прерывании то, что можно сделать в основном цикле программы?

Функция вывода на индикатор

void IND_Update( void )
static unsigned char count = 0;

//зажигаем нужный разряд
if (count == 0) PORT_K |= (1 if (count == 1) PORT_K |= (1 if (count == 2) count = 0;
>

Эта функция будет вызываться в прерывании таймера. В принципе, для экономии ресурсов ее можно было бы сделать встраиваемой.

Пример 5. Код программы с использованием этих функций //программный счетчик секунд
unsigned char counterProg = 0;

int main( void )
IND_Init();

//инициализация таймера Т0
TIMSK = (1 __enable_interrupt ();
while (1) counterProg++;
if (counterProg == 100) counterProg = 0;
IND_Conv(counterProg);
__delay_cycles (8000000);
>
return 0;
>

Создаем два файла – indicator.h и indicator.c. Сохраняем их в папке проекта.
В хидер файле у нас будут директивы условной компиляции, макроопределения и прототипы функций.

Все. Теперь мы можем использовать функции для работы с индикатором в файле main.
Полный код драйвера смотрите в проектах.

Продолжение следует… Скоро будет дополнение к этой статье - описание вольтметра на микроконтроллере – в проекте используется 4-ех разрядный семисегментный индикатор.

Читайте также: