Программа дисплея на сдвиговых регистрах

Тарас Петрович
Offline
Зарегистрирован: 21.11.2015

Доброго времени суток! Собрал четырёхразрядный дисплей на регистрах 595 по схеме с сайта Амперки. При трассировке печатной платы неверно понял задумку автора и перепутал регистры местами. Вместо 1->2->3->4 сделал 4-3-2-1. Дисплей заработал, но цифры стал показывать в обратном порядке (что и понятно). Плату портить не хочется, полез в библиотеку QuadDislay (а управление регистрами как-то хитро сделано, на один всё провод). В файле QuadDislay.h ничего интересно не обнаружил, там только маски цифр, а вот  в QuadDislay.cpp нашел функцию 

void displayDigits(uint8_t pin, uint8_t digit1, uint8_t digit2, uint8_t digit3, uint8_t digit4)
{
    pinMode(pin, OUTPUT);
    //turnOffPWM work here:
    digitalWrite(pin, HIGH);
    sendByte(pin, digit4);//Здесь было digit1
    sendByte(pin, digit3);//Здесь было digit2
    sendByte(pin, digit2);//Здесь было digit3
    sendByte(pin, digit1);//Здесь было digit4
    latch(pin);
}

И поправил в ней порядок загрузки цифр в регистры. Всё заработало верно, кроме функции 

void displayFloat(uint8_t pin, float val, uint8_t precision, bool padZeros)
{
    uint8_t dot = 0x1;
    while (precision) {
        val *= 10;
        --precision;
        dot <<= 1;
    }

    displayInt(pin, (int)val, padZeros, dot);

Которая призвана выводить дробные числе с заданой точностью. При разных значениях точности, точка ведёт себя непредсказуемо, но в свой разряд не попадает. Так вот вопрос, кто б мне помог библиотеку поправить, чтоб точка на место встала, или объясните, где я загнался!?

 

Это файл срр

#include <Arduino.h>

#include "QuadDisplay.h"

#include "pins_arduino.h"


#ifndef _VARIANT_ARDUINO_DUE_X_

#define MACRO_DIGITAL_WRITE(a,b) (fastDigitalWrite(a,b))

    //Fast version of digitalWrite, without using turnOffPWM
    //
void fastDigitalWrite(uint8_t pin, uint8_t val)
{
      //uint8_t timer = digitalPinToTimer(pin);
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    volatile uint8_t *out;

    if (port == NOT_A_PIN) return;

    // If the pin that support PWM output, we need to turn it off
    // before doing a digital write.
    // DELETED. Timer is already off here . Amperka
    // if (timer != NOT_ON_TIMER) turnOffPWM(timer);

    out = portOutputRegister(port);

    uint8_t oldSREG = SREG;
    cli();

    if (val == LOW) {
        *out &= ~bit;
    } else {
        *out |= bit;
    }

    SREG = oldSREG;
}


#else

#define MACRO_DIGITAL_WRITE(a,b) (digitalWrite(a,b))

#endif

const static uint8_t numerals[] = {QD_0, QD_1, QD_2, QD_3, QD_4, QD_5, QD_6, QD_7, QD_8, QD_9};

static void sendByte(uint8_t pin, byte data, byte n = 8)
{
    for (byte i = n; i > 0; i--) {
        if (data & 1) {
            noInterrupts();
            MACRO_DIGITAL_WRITE(pin, LOW);
            MACRO_DIGITAL_WRITE(pin, HIGH);
            interrupts();
            delayMicroseconds(30);
        }
        else {
            MACRO_DIGITAL_WRITE(pin, LOW);
            delayMicroseconds(15);
            MACRO_DIGITAL_WRITE(pin, HIGH);
            delayMicroseconds(60);
        }
        data >>= 1;
    }
}

static void latch(uint8_t pin)
{
    MACRO_DIGITAL_WRITE(pin, LOW);
    delayMicroseconds(60);
    MACRO_DIGITAL_WRITE(pin, HIGH);
    delayMicroseconds(300);
}

void displayDigits(uint8_t pin, uint8_t digit1, uint8_t digit2, uint8_t digit3, uint8_t digit4)
{
    pinMode(pin, OUTPUT);
    //turnOffPWM work here:
    digitalWrite(pin, HIGH);
    sendByte(pin, digit4);//Здесь было digit1
    sendByte(pin, digit3);//Здесь было digit2
    sendByte(pin, digit2);//Здесь было digit3
    sendByte(pin, digit1);//Здесь было digit4
    latch(pin);
}

void displayClear(uint8_t pin)
{
    displayDigits(pin, QD_NONE, QD_NONE, QD_NONE, QD_NONE);
}


void displayInt(uint8_t pin, int val, bool padZeros, uint8_t dots)
{
    uint8_t digits[4] = {0xff, 0xff, 0xff, 0xff};

    if (!padZeros && !val)
        digits[3] = numerals[0];
    else {
        bool negative = val < 0;
        val = abs(val);


        int8_t i;
        for (i = 4; i--; ) {
            uint8_t digit = val % 10;
            digits[i] = (val || padZeros) ? numerals[digit] : 0xff;

            val /= 10;
            if (!val && !padZeros)
                break;
        }

        if (negative)
            digits[max(0, i-1)] = QD_MINUS;

        for (i = 4; i--; ) {
            if (dots & (1 << i))
                digits[4 - i] &= QD_DOT;
        }
    }

    displayDigits(pin, digits[0], digits[1], digits[2], digits[3]);
}

void displayFloat(uint8_t pin, float val, uint8_t precision, bool padZeros)
{
    uint8_t dot = 0x1;
    while (precision) {
        val *= 10;
        --precision;
        dot <<= 1;
    }

    displayInt(pin, (int)val, padZeros, dot);
}

void displayTemperatureC(uint8_t pin, int val, bool padZeros)
{

    uint8_t digits[4] = {0xff, 0xff, QD_DEGREE, QD_C};
    
    if (!padZeros && !val)
        digits[1] = numerals[0];
    else {
        bool negative = val < 0;
        val = abs(val);

        int8_t i;
        for (i = 2; i--; ) {
            uint8_t digit = val % 10;
            digits[i] = (val || padZeros) ? numerals[digit] : 0xff;

            val /= 10;
            if (!val && !padZeros)
                break;
        }

        if (negative)
            digits[max(0, i-1)] = QD_MINUS;
    }
    displayDigits(pin, digits[0], digits[1], digits[2], digits[3]);
}

Это файл .h

/*
 * Copyright (c) 2014 by Amperka LLC
 * QuadDisplay Driver Library
 * Authors:
 *   - Victor Nakoryakov <victor at amperka.ru>
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of either the GNU General Public License version 2
 * or the GNU Lesser General Public License version 2.1, both as
 * published by the Free Software Foundation.
 */

#ifndef QUAD_DISPLAY
#define QUAD_DISPLAY

#include <inttypes.h> 

/*

    ___7___
   /       \
  |         |
 2|         |6
   \___1___/
   /       \
  |         |
 3|         |5
   \___4___/
               *0
 */

#define QD_NONE  0b11111111
#define QD_DOT   0b11111110
#define QD_MINUS 0b11111101

#define QD_UNDERSCORE 0b11101111
#define QD_DEGREE     0b00111001

#define QD_0 0b00000011
#define QD_1 0b10011111
#define QD_2 0b00100101
#define QD_3 0b00001101
#define QD_4 0b10011001
#define QD_5 0b01001001
#define QD_6 0b01000001
#define QD_7 0b00011111
#define QD_8 0b00000001
#define QD_9 0b00001001

#define QD_A 0b00010001
#define QD_a 0b00000101
#define QD_b 0b11000001
#define QD_C 0b01100011
#define QD_c 0b11100101
#define QD_d 0b10000101
#define QD_E 0b01100001
#define QD_f 0b01110001
#define QD_F QD_f
#define QD_H 0b10010001
#define QD_h 0b11010001
#define QD_I QD_1
#define QD_J 0b10001111
#define QD_L 0b11100011
#define QD_n 0b11010101
#define QD_o 0b11000101
#define QD_O QD_0
#define QD_P 0b00110001
#define QD_r 0b11110101
#define QD_S 0b01001001
#define QD_t 0b11100001
#define QD_u 0b11000111
#define QD_U 0b10000011
#define QD_Y 0b10001001


void displayInt(uint8_t pin, int val, bool padZeros=false, uint8_t dots=0x00);
void displayFloat(uint8_t pin, float val, uint8_t precision, bool padZeros=false);
void displayDigits(uint8_t pin, uint8_t digit1, uint8_t digit2, uint8_t digit3, uint8_t digit4);
void displayClear(uint8_t pin);

void displayTemperatureC(uint8_t pin, int val, bool padZeros=false);

#endif

Это схема

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Видимо, не совсем непредсказуемо, а "наоборот"? Т.е. позиция точки правильная если считать не слева направо, а справа налево. Так?

Если так, попробуйте её перевернуть. Вы же все цифры перевернули, а точка чем хуже?

Вместо

void displayFloat(uint8_t pin, float val, uint8_t precision, bool padZeros)
{
    uint8_t dot = 0x1;
    while (precision) {
        val *= 10;
        --precision;
        dot <<= 1;
    }

    displayInt(pin, (int)val, padZeros, dot);

напишите

void displayFloat(uint8_t pin, float val, uint8_t precision, bool padZeros)
{
    uint8_t dot = 0x08;   // !!!!!
    while (precision) {
        val *= 10;
        --precision;
        dot >>= 1;       // !!!!!!
    }

    displayInt(pin, (int)val, padZeros, dot);

Отпишите, что вышло и, если проблема не ушла, пожалуйста проведите такой эксперимент.

1. Возьмите одно и то же число в последовательно выведите его с точностями от 0 до 3.
2. Зафискисруйте и опишите в какую позицию попадала при этом точка (при каждой точности).

Тарас Петрович
Offline
Зарегистрирован: 21.11.2015

Уж и не думал, что тема оживёт! Спасибо за совет, на днях всё испробую, отпишусь. Дисплей у меня работает, но точка ведёт себя непостижимым образом. Я пока сделал так: Раз в функцию  displayInt передаётся переменная dot (я так понимаю, это маска точек), я пробовал организовать вывод информации этой функцией, но вручную загонял в неё 0b00001111. Должна же работать, нет, так удаётся засветить только точки в третьем и четвёртом разряде. Первый- горит всегда, второй-никогда. Возвращаю библиотечный файл в исходный вид, разряды "переворачиваются", за то точки моим способом (да и штатным тоже) попадают на свои разряды. И точка второго раряда оживает! Первый по-прежнему горит постоянно. Вобщем, я голову сломал. Теперь сделаю как советуете и опишу точно результат. Сам принцип такой схемы мне интересен. Только мне предстоит понять суть построения программы для него, чтобы я мог, например, увеличить количество разрядов. Библиотеку, видимо писали опытные программисты, могли что-то упростить, сократить, а в результате код мне не понятен.