Configuration Wizard в KEIL. Ассемблер А51, подбор битовых масок для вывода на семисегментный индикатор

На странице помощи по Configuration Wizard упор сделан на С программировании. Но мастер конфигураций легко встраивается и в чисто ассемблерные проекты. При этом следует придерживаться ассемблерной орфографии. Ниже приведен пример подобного мастера.
Семисегментный индикатор часто подключают к шинам контроллера руководствуясь только простотой разводки печатной платы. Поэтому вывод на индикатор требует соответствующей кодировки выводимых символов. Облегчить их получение и помогает мастер конфигураций.
Подключив данный файл в проект (CW_DISPBITS.a51) и открыв его, щелкаем по закладке «Configuration Wizard», затем по кнопке «Expand All».

Код мастера:
;= Битовые маски для семисегментного дисплея ==================;
; A
; --
; F| |B
; G--
; E| |C
; -- .H
; D
;
; *** <<< Use Configuration Wizard in Context Menu >>> ***
;- Header ------------------------------------------------------;
; <h> Make Display Segments
;- Segment A ---------------------------------------------------;
; <e> Enable Segment A
; <i> Enable Segment A for making
Enb_A EQU 0
; <o> Bit A
; <i> Top-Middle segment
; <0=> A=0, - - - - - - - X
; <1=> A=1, - - - - - - X -
; <2=> A=2, - - - - - X - -
; <3=> A=3, - - - - X - - -
; <4=> A=4, - - - X - - - -
; <5=> A=5, - - X - - - - -
; <6=> A=6, - X - - - - - -
; <7=> A=7, X - - - - - - -
Bit_A EQU 0
IF (Enb_A = 1)
Seg_A EQU Bit_A << 1
ELSE
Seg_A EQU 0
ENDIF
; </e>
;- Segment B ---------------------------------------------------;
;- Segment C ---------------------------------------------------;
;- Segment D ---------------------------------------------------;
;- Segment E ---------------------------------------------------;
;- Segment F ---------------------------------------------------;
;- Segment G ---------------------------------------------------;
;- Segment H ---------------------------------------------------;
; </h>
; *** <<< end of configuration section >>> ***
После тега <h> идет общий заголовок «Make Display Segments» мастера. Ему должен соответствовать закрывающий тег </h>.
Затем после тега <e> идет группа настроек с общим разрешающим чекбоксом. Если чекбокс не отмечен, заголовок группы и все входящие в группу настройки будут серыми (неактивными). Здесь также требуется закрывающий тег </e>. Состояние чекбокса отображается в константе Enb_A. Пока чекбокс не отмечен — Enb_A EQU 0, если отмечен — Enb_A EQU 1.
В группу входит только одна настройка — после тега <o> размещен выпадающий список. Результат выбора — индекс выбранной строки. Закрывающий тег не требуется. Состояние списка отображается в константе Bit_A.
Строки после тега <i> — подсказки. Закрывающий тег не требуется.
Далее средствами условной компиляции обрабатываются константы Enb_A и Bit_A. Если чекбокс отмечен, формируется требуемая битовая маска Seg_A, если нет — маска содержит 0.
Маски остальных сегментов формируются аналогично. Конец мастера.
Затем из масок отдельных сегментов формируются маски символов для семисегментного индикатора. Общепринятое начертание цифр:
;-- Digits -----------------------------------------------------;
CH_0 EQU Seg_A | Seg_B | Seg_C | Seg_D | Seg_E | Seg_F
CH_1 EQU Seg_B | Seg_C
CH_2 EQU Seg_A | Seg_B | Seg_D | Seg_E | Seg_G
CH_3 EQU Seg_A | Seg_B | Seg_C | Seg_D | Seg_G
CH_4 EQU Seg_B | Seg_C | Seg_F | Seg_G
CH_5 EQU Seg_A | Seg_C | Seg_D | Seg_F | Seg_G
CH_6 EQU Seg_A | Seg_C | Seg_D | Seg_E | Seg_F | Seg_G
CH_7 EQU Seg_A | Seg_B | Seg_C
CH_8 EQU Seg_A | Seg_B | Seg_C | Seg_D | Seg_E | Seg_F | Seg_G
CH_9 EQU Seg_A | Seg_B | Seg_C | Seg_D | Seg_F | Seg_G
С символами латинского алфавита сложнее, некоторые не так просто отразить на семисегментном индикаторе. Вот один из вариантов:

И его кодировки:
;-- Symbols --------------------------------------------------- ;
CH_A EQU Seg_A | Seg_B | Seg_C | Seg_E | Seg_F
CH_B EQU Seg_C | Seg_D | Seg_E | Seg_F | Seg_G
CH_C EQU Seg_A | Seg_D | Seg_E | Seg_F
CH_D EQU Seg_B | Seg_C | Seg_D | Seg_E | Seg_G
CH_E EQU Seg_A | Seg_D | Seg_E | Seg_F | Seg_G
CH_F EQU Seg_A | Seg_E | Seg_F | Seg_G
CH_G EQU Seg_A | Seg_C | Seg_D | Seg_E | Seg_F
CH_H EQU Seg_B | Seg_C | Seg_E | Seg_F | Seg_G
CH_I EQU Seg_A | Seg_D | Seg_E
CH_J EQU Seg_A | Seg_C | Seg_D
CH_K EQU Seg_B | Seg_E | Seg_F | Seg_G
CH_L EQU Seg_D | Seg_E | Seg_F
CH_M EQU Seg_A | Seg_C | Seg_E | Seg_G
CH_N EQU Seg_C | Seg_E | Seg_G
CH_O EQU Seg_C | Seg_D | Seg_E | Seg_G
CH_P EQU Seg_A | Seg_B | Seg_E | Seg_F | Seg_G
CH_Q EQU Seg_A | Seg_B | Seg_C | Seg_F | Seg_G
CH_R EQU Seg_E | Seg_G
CH_S EQU Seg_A | Seg_C | Seg_D | Seg_F | Seg_G
CH_T EQU Seg_D | Seg_E | Seg_F | Seg_G
CH_U EQU Seg_B | Seg_C | Seg_D | Seg_E | Seg_F
CH_V EQU Seg_C | Seg_D | Seg_E
CH_W EQU Seg_B | Seg_D | Seg_F | Seg_G
CH_X EQU Seg_A | Seg_C | Seg_D | Seg_E
CH_Y EQU Seg_B | Seg_C | Seg_D | Seg_F | Seg_G
CH_Z EQU Seg_A | Seg_D | Seg_G
CH_Pt EQU Seg_H ; Точка
CH_Tr EQU Seg_G ; Тире
CH_Gr EQU Seg_A | Seg_B | Seg_F | Seg_G ; Градус Цельсия
Т.к. мастер конфигураций обрабатывается препроцессором на этапе компиляции, он не занимает ни байта во флеш. К примеру после компиляции проекта только с этим файлом получилось:

Это происходит потому, что мастер только назначает значения констант, самих констант он не определяет. Для того, чтобы можно было их определить в другом файле, необходимо экспортировать их символьные имена:
PUBLIC CH_0, CH_1, CH_2, CH_3, CH_4, CH_5, CH_6, CH_7, CH_8, CH_9
PUBLIC CH_A, CH_B, CH_C, CH_D, CH_E, CH_F, CH_G, CH_H, CH_I
PUBLIC CH_J, CH_K, CH_L, CH_M, CH_N, CH_O, CH_P, CH_Q, CH_R
PUBLIC CH_S, CH_T, CH_U, CH_V, CH_W, CH_X, CH_Y, CH_Z, CH_Tr, CH_Gr, CH_Pt
Теперь в файле, в котором нужно выводить цифры, необходимо сначала импортировать нужные символьные имена, затем определить соответствующий контейнер для кодов символов:
NAME CW_TEST
EXTRN NUMBER (CH_0, CH_1, CH_2, CH_3, CH_4, CH_5, CH_6, CH_7, CH_8, CH_9)
CONST SEGMENT CODE ; Таблица во Flash
RSEG CONST
TBL_DIGITS: ; 0-9
DB CH_0, CH_1, CH_2, CH_3, CH_4, CH_5, CH_6, CH_7, CH_8, CH_9
END
Соответственно сразу для них и место выделится:

- +2
- 13 марта 2015, 23:16
- anakost
#ifndef _DISP_7SEG_H_
#define _DISP_7SEG_H_
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include "conf.h"
#define DISP7S_SPORT0 PORTD
#define DISP7S_SDIR0 DDRD
#define DISP7S_SPORT1 PORTC
#define DISP7S_SDIR1 DDRC
#define DISP7S_DPORT0 PORTC
#define DISP7S_DDIR0 DDRC
#define DISP7S_DPORT1 PORTA
#define DISP7S_DDIR1 DDRA
#define DISP7S_DINV 0x1E00
//#define DISP7S_DINV 0xE080
#define DISP7S_SINV 0x0000
#define DISP7S_DMASK 0xFE80
#define DISP7S_SMASK 0x7CE0
#define DISP7S_DIGITS 8
#define DISP7S_DOT 0x80
#define DISP7S_UP 0x01
#define DISP7S_LO 0x08
#define DISP7S_MD 0x40
#define DISP7S_UR 0x02
#define DISP7S_LR 0x04
#define DISP7S_UL 0x20
#define DISP7S_LL 0x10
#define DISP7S_0 (DISP7S_UP | DISP7S_UR | DISP7S_LR | DISP7S_LO | DISP7S_LL | DISP7S_UL)
#define DISP7S_1 (DISP7S_UR | DISP7S_LR)
#define DISP7S_2 (DISP7S_UP | DISP7S_UR | DISP7S_MD | DISP7S_LL | DISP7S_LO)
#define DISP7S_3 (DISP7S_UP | DISP7S_MD | DISP7S_LO | DISP7S_UR | DISP7S_LR)
#define DISP7S_4 (DISP7S_UL | DISP7S_MD | DISP7S_UR | DISP7S_LR)
#define DISP7S_5 (DISP7S_UP | DISP7S_UL | DISP7S_MD | DISP7S_LR | DISP7S_LO)
#define DISP7S_6 (DISP7S_UP | DISP7S_MD | DISP7S_LO | DISP7S_UL | DISP7S_LL | DISP7S_LR)
#define DISP7S_7 (DISP7S_UP | DISP7S_UR | DISP7S_LR)
#define DISP7S_8 (DISP7S_UP | DISP7S_MD | DISP7S_LO | DISP7S_UL | DISP7S_UR | DISP7S_LR | DISP7S_LL)
#define DISP7S_9 (DISP7S_UP | DISP7S_MD | DISP7S_LO | DISP7S_UL | DISP7S_UR | DISP7S_LR)
#define DISP7S_A (DISP7S_UP | DISP7S_MD | DISP7S_UL | DISP7S_UR | DISP7S_LR | DISP7S_LL)
#define DISP7S_B (DISP7S_MD | DISP7S_LO | DISP7S_UL | DISP7S_LR | DISP7S_LL)
#define DISP7S_C (DISP7S_UP | DISP7S_LO | DISP7S_UL | DISP7S_LL)
#define DISP7S_D (DISP7S_MD | DISP7S_LO | DISP7S_UR | DISP7S_LR | DISP7S_LL)
#define DISP7S_E (DISP7S_UP | DISP7S_MD | DISP7S_LO | DISP7S_UL | DISP7S_LL)
#define DISP7S_F (DISP7S_UP | DISP7S_MD | DISP7S_UL | DISP7S_LL)
#define DISP7S_G (DISP7S_UP | DISP7S_LO | DISP7S_UL | DISP7S_LL | DISP7S_LR)
#define DISP7S_H (DISP7S_MD | DISP7S_UL | DISP7S_UR | DISP7S_LR | DISP7S_LL)
#define DISP7S_I (DISP7S_UL | DISP7S_LL)
#define DISP7S_J (DISP7S_UR | DISP7S_LR | DISP7S_LO)
#define DISP7S_L (DISP7S_UL | DISP7S_LL | DISP7S_LO)
#define DISP7S_O DISP7S_0
#define DISP7S_P (DISP7S_UP | DISP7S_MD | DISP7S_UL | DISP7S_UR | DISP7S_LL)
#define DISP7S_S DISP7S_5
#define DISP7S_T (DISP7S_MD | DISP7S_LO | DISP7S_UL | DISP7S_LL)
#define DISP7S_U (DISP7S_UR | DISP7S_LR | DISP7S_LO | DISP7S_LL | DISP7S_UL)
#define DISP7S_Y (DISP7S_MD | DISP7S_LO | DISP7S_UL | DISP7S_UR | DISP7S_LR)
#define DISP7S_Z DISP7S_2
#define DISP7S_DIV (DISP7S_UP | DISP7S_MD | DISP7S_LO)
#define DISP7S_LP (DISP7S_UP | DISP7S_LO | DISP7S_UL | DISP7S_LL)
#define DISP7S_RP (DISP7S_UP | DISP7S_LO | DISP7S_UR | DISP7S_LR)
#define DISP7S_MINUS (DISP7S_MD)
#define DISP7S_SNAKE_0 (DISP7S_UL | DISP7S_UP)
#define DISP7S_SNAKE_1 (DISP7S_UP | DISP7S_UR)
#define DISP7S_SNAKE_2 (DISP7S_UR | DISP7S_MD)
#define DISP7S_SNAKE_3 (DISP7S_MD | DISP7S_LL)
#define DISP7S_SNAKE_4 (DISP7S_LL | DISP7S_LO)
#define DISP7S_SNAKE_5 (DISP7S_LO | DISP7S_LR)
#define DISP7S_SNAKE_6 (DISP7S_LR | DISP7S_MD)
#define DISP7S_SNAKE_7 (DISP7S_MD | DISP7S_UL)
extern void disp_7seg_init();
extern void disp_7seg_digit(char n);
extern void disp_7seg_segment(char s, char n);
extern void disp_7seg_off();
extern void disp_7seg_scan();
extern void disp_7seg_str(char *str, char i, char n);
extern volatile char disp_7seg_bfr[DISP7S_DIGITS];
extern volatile char disp_7seg_cur;
#endif
#include <avr/pgmspace.h>
#include <string.h>
#include "timer.h"
#include "uart.h"
#include "disp_7seg.h"
#include "global.h"
volatile char disp_7seg_bfr[DISP7S_DIGITS];
volatile char disp_7seg_cur;
const char disp_7seg_ct[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, // !"#
0x00, 0x00, 0x00, 0x00, //$%&'
DISP7S_LP, DISP7S_RP, 0x00, 0x00, //()*+
DISP7S_DOT, DISP7S_MINUS, DISP7S_DOT, DISP7S_DIV, //,-./
DISP7S_0, DISP7S_1, DISP7S_2, DISP7S_3, //0123
DISP7S_4, DISP7S_5, DISP7S_6, DISP7S_7, //4567
DISP7S_8, DISP7S_9, DISP7S_DOT, DISP7S_DOT, //89:;
0x00, 0x00, 0x00, 0x00, //<=>?
0x00, DISP7S_A, DISP7S_B, DISP7S_C, //@ABC
DISP7S_D, DISP7S_E, DISP7S_F, DISP7S_G, //DEFG
DISP7S_H, DISP7S_I, DISP7S_J, DISP7S_H, //HIJK
DISP7S_L, 0x00, 0x00, DISP7S_O, //LMNO
DISP7S_P, 0x00, 0x00, DISP7S_S, //PQRS
DISP7S_T, DISP7S_U, 0x00, 0x00, //TUVW
0x00, DISP7S_Y, DISP7S_Z, DISP7S_LP, //XYZ[
0x00, DISP7S_RP, DISP7S_UP, DISP7S_LO, //\]^_
DISP7S_UL, DISP7S_A, DISP7S_B, DISP7S_C, //`abc
DISP7S_D, DISP7S_E, DISP7S_F, DISP7S_G, //DEFG
DISP7S_H, DISP7S_I, DISP7S_J, 0x00, //HIJK
DISP7S_L, 0x00, 0x00, DISP7S_O, //LMNO
DISP7S_P, 0x00, 0x00, DISP7S_S, //PQRS
DISP7S_T, DISP7S_U, 0x00, 0x00, //TUVW
0x00, DISP7S_Y, DISP7S_Z, DISP7S_LP, //XYZ[
DISP7S_I, DISP7S_RP, DISP7S_MINUS, DISP7S_DOT //|}~.
};
#define DISP7S_D_0 0x2000
#define DISP7S_D_1 0x4000
#define DISP7S_D_2 0x8000
#define DISP7S_D_3 0x0080
#define DISP7S_D_4 0x0200
#define DISP7S_D_5 0x0400
#define DISP7S_D_6 0x0800
#define DISP7S_D_7 0x1000
const int disp_7seg_d[DISP7S_DIGITS] PROGMEM = {
(DISP7S_D_0 ^ DISP7S_DINV), (DISP7S_D_1 ^ DISP7S_DINV),
(DISP7S_D_2 ^ DISP7S_DINV), (DISP7S_D_3 ^ DISP7S_DINV),
(DISP7S_D_4 ^ DISP7S_DINV), (DISP7S_D_5 ^ DISP7S_DINV),
(DISP7S_D_6 ^ DISP7S_DINV), (DISP7S_D_7 ^ DISP7S_DINV)
};
const char disp_7seg_i[DISP7S_DIGITS] = {
0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF
};
const int disp_7seg_s[] = {
0x0020 ^ DISP7S_SINV, 0x0040 ^ DISP7S_SINV,
0x0080 ^ DISP7S_SINV, 0x0400 ^ DISP7S_SINV,
0x0800 ^ DISP7S_SINV, 0x1000 ^ DISP7S_SINV,
0x2000 ^ DISP7S_SINV, 0x4000 ^ DISP7S_SINV
};
void disp_7seg_init()
{
disp_7seg_cur = 0;
memset(disp_7seg_bfr, 0, DISP7S_DIGITS);
DISP7S_SDIR0 |= (DISP7S_SMASK & 0xFF);
DISP7S_DDIR0 |= (DISP7S_DMASK & 0xFF);
DISP7S_SDIR1 |= (DISP7S_SMASK >> 8);
DISP7S_DDIR1 |= (DISP7S_DMASK >> 8);
}
void disp_7seg_shift_left()
{
memmove(disp_7seg_bfr, disp_7seg_bfr + 1, DISP7S_DIGITS);
}
void disp_7seg_shift_right()
{
memmove(disp_7seg_bfr + 1, disp_7seg_bfr, DISP7S_DIGITS);
}
void disp_7seg_digit(char n)
{
DISP7S_DPORT0 = (DISP7S_DPORT0 & (~( DISP7S_DMASK & 0xFF) ) ) | pgm_read_byte( (char*)(&disp_7seg_d[n]) + 0);
DISP7S_DPORT1 = (DISP7S_DPORT1 & (~( DISP7S_DMASK >> 8 ) ) ) | pgm_read_byte( (char*)(&disp_7seg_d[n]) + 1);
}
void disp_7seg_off()
{
DISP7S_DPORT0 = ( DISP7S_DPORT0 & ( (~DISP7S_DMASK) & 0xFF) ) | ( ( (~(DISP7S_DINV ^ DISP7S_DMASK)) & DISP7S_DMASK) & 0xFF );
DISP7S_DPORT1 = ( DISP7S_DPORT1 & ( (~DISP7S_DMASK) >> 8) ) | ( ( (~(DISP7S_DINV ^ DISP7S_DMASK)) & DISP7S_DMASK) >> 8 );
}
void disp_7seg_segment(char s, char n)
{
int d = 0;
s ^= disp_7seg_i[n];
if( s & 0x01 ) d |= disp_7seg_s[0];
if( s & 0x02 ) d |= disp_7seg_s[1];
if( s & 0x04 ) d |= disp_7seg_s[2];
if( s & 0x08 ) d |= disp_7seg_s[3];
if( s & 0x10 ) d |= disp_7seg_s[4];
if( s & 0x20 ) d |= disp_7seg_s[5];
if( s & 0x40 ) d |= disp_7seg_s[6];
if( s & 0x80 ) d |= disp_7seg_s[7];
DISP7S_SPORT0 = (DISP7S_SPORT0 & (~( DISP7S_SMASK & 0xFF) ) ) | (d & 0xFF);
DISP7S_SPORT1 = (DISP7S_SPORT1 & (~( DISP7S_SMASK >> 8) ) ) | (d >> 8);
}
void disp_7seg_scan()
{
char n = disp_7seg_cur;
disp_7seg_off();
disp_7seg_segment(disp_7seg_bfr[n], n);
disp_7seg_digit(n);
n ++;
disp_7seg_cur = (n >= DISP7S_DIGITS)? 0 : n;
}
void disp_7seg_str(char *str, char i, char n)
{
char *bfr = disp_7seg_bfr + i;
unsigned char c;
if( n == 0 ) n = -1;
while(n)
{
c = *(str++);
if( c == 0 ) break;
c = pgm_read_byte( &disp_7seg_ct[ (c - 0x20) & 0x7F ] );
if( c == DISP7S_DOT )
{
if( i == 0 )
{
*bfr = DISP7S_DOT;
i++;
}
else *(bfr-1) |= DISP7S_DOT;
}
else
{
*bfr = c;
bfr++;
i++;
if(i > DISP7S_DIGITS) break;
}
n--;
}
}
Комментарии (5)
RSS свернуть / развернуть