Pic16f684 &双七段显示程序:C中的随机数生成器 [英] Pic16f684 & dual seven seg display program: random number generator in C

查看:104
本文介绍了Pic16f684 &双七段显示程序:C中的随机数生成器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将此代码转换为能够生成 1-56 的随机数.我会理解,但因为程序必须来回切换才能显示两个数字,所以我很困惑.

I'm trying to convert this code to be able to generate random numbers 1-56. I would understand, but because the program has to switch back and forth to be able to show both digits, I'm confused.

我知道在某些方面,我可以使用 rand() 来选择.

I know in some respect, I can use rand() to choose.

我最终将使用此代码与 lcd 屏幕结合来显示数字以及双七段显示,但现在,只是想弄清楚对 PIC16F684 进行编程以在 dua84l 七上生成随机数段显示

I will eventually use this code in junction with an lcd screen to display the numbers as well as the dual seven segment display, but for now, just trying to figure out to program a PIC16F684 to generate the random number on the dua84l seven seg display

下面是电路和代码.未包含在图中,但在代码中是 RA3 &RA4 具有清除显示或生成下一位数字的按钮.

Below is the circuit and code. Not included in the diagram, but in the code is RA3 & RA4 have buttons that clear the display or generate the next digit.

提供的程序在按下按钮时显示 00-0xFF.改写程序可能更容易些,但我就是不明白

The program supplied displays 00-0xFF as a button gets pushed. It may be easier to rewrite the program, but I just dont understand it

#include <xc.h>
/*
*
*
* 6/30/2020
/******************************************/
/* ------------------------------------------- */
/* Software/Hardware Interface: */
/* ------------------------------------------- */
/* */
/* Select Right Digit using >> RA0 */
/* Select Left Digit using >> RA1 */
/* */
/* Segment a >> RA5 */
/* Segment b >> RC5 */
/* Segment c >> RC4 */
/* Segment d >> RC3 */
/* Segment e >> RC2 */
/* Segment f >> RC1 */
/* Segment g >> RC0 */
/* ------------------------------------------- */


void PORTA_init(void)
{
    PORTA = 0;          //  All PORTA Pins are low
    CMCON0 = 7;         //  Turn off Comparators
    ANSEL = 0;          //  Turn off ADC
    //TRISA = 0b001111;   //  RA4 and 5 are outputs; RA0,1,2, and 3 are input
    return;
}
/******** END OF PORTA_init ****************************/
void delay_routine(void)
{
    int i, j;
        for (i = 0; i<2000; i++);
        for (j = 0; j <2000;j++);
    return;
}
/******** END OF delay_20ms *************************/
// CONFIG --- Configuration Word --- START
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
// CONFIG --- Configuration Word --- END

int i, j;
int DisplayValue, DisplayLED;

const char LEDDigit[] = {
   0b0000001, // "0"
   0b1001111, // "1"
   0b0010010, // "2"
   0b0000110, // "3"
   0b1001100, // "4"
   0b0100100, // "5"
   0b0100000, // "6"
   0b0001111, // "7"
   0b0000000, // "8"
   0b0001100, // "9"
   0b0001000, // "A"
   0b0000000, // "b"
   0b0110001, // "C"
   0b0000001, // "d"
   0b0110000, // "E"
   0b0111000
}; // "F"  


main()
{
 PORTA = 0;
 PORTC = 0;
 CMCON0 = 7; // Turn off Comparators 
 ANSEL = 0; // Turn off ADC 
 TRISA = 0b011101; // RA5 and RA1 are outputs
 TRISC = 0b000000; 
         
 DisplayValue = 0; // Start Displaying at 0x00 
 DisplayLED = 0; // Display the 1s first
 while(1 == 1) // Loop Forever 
 {
        if (0 == DisplayLED) // True, then display right digit
        { 
            RA5 = LEDDigit[DisplayValue & 0x0F] >> 6;
                // Clears display bits 4 - 7 of DisplayValue,
                // then selects bit 7 of LEDDigit
            PORTC = LEDDigit[DisplayValue & 0x0F] & 0x03F;
                // clears display bits 4 - 7 of DisplayValue,
                // then selects bits 0 - 6 of LEDDigit 
        }
        else 
        { 
            RA5 = LEDDigit[(DisplayValue >> 4) & 0x0F] >> 6;
            PORTC = LEDDigit[(DisplayValue >> 4) & 0x0F] & 0x03F;
        } // 
        TRISA = TRISA ^ 0b000011; // Swap Left/Right (RA0 and RA1)
        PORTA = PORTA & 0b111100; // Make Sure Bits are Low 
        DisplayLED = DisplayLED ^ 1; // Other Digit Next

        NOP(); // Used for 10 ms Timing 
        for (i = 0; i < 30; i++);//10ms Delay Loop 
        NOP(); // Used for 10 ms Timing

        if (RA3 == 0) 
        {
            delay_routine();
            DisplayValue++; // Increment the Counter 
            delay_routine();
            
            } //
        if (RA4 == 0)
        {
            delay_routine();
            DisplayValue=0;
            delay_routine();
            
        }
    } 
}

推荐答案

@tjpplay,

您发布的代码有一些微妙的问题,并且无法交替启用数字驱动程序.

The code you posted has some subtle issues and a failure to alternate the digit driver enables.

您检测按钮按下的方法会破坏数字多路复用器的时序并导致闪烁.

Your method to detect a button press disrupts the digit multiplexer timing and causes flicker.

将数字驱动器连接到用于在线串行编程器 (ICSP) 的 PGC 和 PGD 引脚使电路编程变得困难.在线调试 (ICD) 不适用于此实现.

With the digit drivers connected to the PGC and PGD pins used for In-Circuit-Serial-Programmer(ICSP) makes in circuit programming difficult. In-Circuit-Debug(ICD) will not work with this implementation.

该代码通过仅使用 8 位写入 PORTA 和 PORTC 寄存器避免了新玩家的读取-修改-写入 (RMW) 陷阱.

The code avoids the Read-Modify-Write(RMW) trap for new players by only using 8-bit writes to the PORTA and PORTC registers.

使用允许 C 编译器进行单个位设置和清除的语法可能会给 PIC16F684 等控制器带来 RMW 问题,尤其是在直接驱动 LED 时.

Using syntax that allows the C compiler to do single bit sets and clears can have a RMW issue for controllers like the PIC16F684 especially when driving LED directly.

我认为此代码可能适用于您的硬件:

I think that this code may work with your hardware:

/*
 * File:   main.c
 * Author: dan1138
 * Target: PIC16F684
 * Compiler: XC8 v2.20
 * IDE: MPLABX v5.25
 * 
 * Description:
 *
 * Created on July 21, 2020, 3:45 PM
 * 
 *                            PIC16F684
 *                  +------------:_:------------+
 *         GND -> 1 : VDD                   VSS : 14 <- 5v0
 * SEG_a_DRIVE <> 2 : RA5/T1CKI     PGD/AN0/RA0 : 13 <> DIGIT_DRIVE_2
 *         SW2 <> 3 : RA4/AN3       PGC/AN1/RA1 : 12 <> DIGIT_DRIVE_1
 *         SW1 -> 4 : RA3/VPP           AN2/RA2 : 11 <> 
 * SEG_b_DRIVE <> 5 : RC5/CPP1          AN4/RC0 : 10 <> SEG_g_DRIVE
 * SEG_c_DRIVE <> 6 : RC4/C2OUT         AN5/RC1 : 9  <> SEG_f_DRIVE
 * SEG_d_DRIVE <> 7 : RC3/AN7           AN6 RC2 : 8  <> SEG_e_DRIVE
 *                  +---------------------------:
 *                             DIP-14
 */

// CONFIG --- Configuration Word --- START
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
// CONFIG --- Configuration Word --- END

#include <xc.h>
#include <stdlib.h>

/* Oscillator frequency we will select with the OSCCON register */
#define _XTAL_FREQ (4000000ul)
/*
 * Segment locations
 * of an LED display
 *      ---a---
 *     :       :
 *     f       b
 *     :       :
 *      ---g---
 *     :       :
 *     e       c
 *     :       :
 *      ---d---
 */
const unsigned char LEDDigit[] = {
//     abcdefg, Segment on = 0
    0b00000001, // "0"
    0b01001111, // "1"
    0b00010010, // "2"
    0b00000110, // "3"
    0b01001100, // "4"
    0b00100100, // "5"
    0b00100000, // "6"
    0b00001111, // "7"
    0b00000000, // "8"
    0b00001100, // "9"
    0b00001000, // "A"
    0b01100000, // "b"
    0b00110001, // "C"
    0b01000010, // "d"
    0b00110000, // "E"
    0b00111000  // "F"  
}; 


void main(void) 
{
    unsigned char DisplayValue, DisplayLED, DigitSegments;
    unsigned char LoopCount;
    
    PORTA = 0;
    PORTC = 0;
    CMCON0 = 7;                 // Turn off Comparators 
    ANSEL = 0;                  // Turn off ADC 
    
    __delay_ms(500);            // wait for ICD before making PGC and PGD outputs;
    TRISA = 0b011100;           // RA5, RA1, RA0 are outputs
    TRISC = 0b000000; 
    OPTION_REGbits.nRAPU = 0;   // Enable weak pull-up on PORTA
    WPUA = 0;                   // Turn off all pull-ups
    WPUAbits.WPUA4 = 1;         // Turn on RA4 pull-up
    
         
    DisplayValue = 0;           // Start Displaying at 0x00 
    DisplayLED = 0;             // Display the 1s first
    LoopCount = 0;
    
    for(;;)
    {
        PORTC = 0xFF;   // turn off all segment drivers
        PORTA = 0xFF;   // and digit drivers
        if (1 == (DisplayLED & 1))
        {
            DigitSegments = LEDDigit[(DisplayValue >> 4) & 0x0F];
            if(DigitSegments & 0b1000000)
            {
                PORTA = 0b111110;   // turn on Digit driver 2
            } 
            else 
            {
                PORTA = 0b011110;   // turn on Digit driver 2 and SEG_a_DRIVER
            }
        }
        else
        {
            DigitSegments = LEDDigit[DisplayValue & 0x0F];
            if(DigitSegments & 0b1000000)
            {
                PORTA = 0b111101;   // turn on Digit driver 1
            } 
            else 
            {
                PORTA = 0b011101;   // turn on Digit driver 1 and SEG_a_DRIVER
            }
        }
        PORTC = DigitSegments;      // turn on segment drivers b to g
        DisplayLED++;               // select next digit

        __delay_ms(10);             // Show digit for 10 milliseconds
        
        if(0 == PORTAbits.RA3)      // is SW1 pressed?
        {
            LoopCount++;
            if(LoopCount == 1)
            {
                DisplayValue++;     // Increment display value every 500 milliseconds
            }
            if(LoopCount >= 50)
            {
                LoopCount = 0;
            }
        }
        else
        {
            LoopCount = 0;
        }

        if(0 == PORTAbits.RA4)      // is SW2 pressed?
        {
            DisplayValue = 0;       // Reset display value to zero
            LoopCount = 0;
        }
    }
}

这就是我如何更改上述代码以生成您要求的随机数:

This is how I would chnage the above code to produce the random numbers you asked for:

void main(void) 
{
    unsigned char DisplayValue, DisplayLED, DigitSegments;
    unsigned char LoopCount;
    unsigned int  Temp;
    
    PORTA = 0;
    PORTC = 0;
    CMCON0 = 7;                 // Turn off Comparators 
    ANSEL = 0;                  // Turn off ADC 
    
    __delay_ms(500);            // wait for ICD before making PGC and PGD outputs;
    TRISA = 0b011100;           // RA5, RA1, RA0 are outputs
    TRISC = 0b000000; 
    OPTION_REGbits.nRAPU = 0;   // Enable weak pull-up on PORTA
    WPUA = 0;                   // Turn off all pull-ups
    WPUAbits.WPUA4 = 1;         // Turn on RA4 pull-up
    
         
    DisplayValue = 0;           // Start Displaying at 0x00 
    DisplayLED = 0;             // Display the 1s first
    LoopCount = 0;
    srand(0x1234);
    
    for(;;)
    {
        PORTC = 0xFF;   // turn off all segment drivers
        PORTA = 0xFF;   // and digit drivers
        if (1 == (DisplayLED & 1))
        {
            DigitSegments = LEDDigit[(DisplayValue >> 4) & 0x0F];
            if(DigitSegments & 0b1000000)
            {
                PORTA = 0b111110;   // turn on Digit driver 2
            } 
            else 
            {
                PORTA = 0b011110;   // turn on Digit driver 2 and SEG_a_DRIVER
            }
        }
        else
        {
            DigitSegments = LEDDigit[DisplayValue & 0x0F];
            if(DigitSegments & 0b1000000)
            {
                PORTA = 0b111101;   // turn on Digit driver 1
            } 
            else 
            {
                PORTA = 0b011101;   // turn on Digit driver 1 and SEG_a_DRIVER
            }
        }
        PORTC = DigitSegments;      // turn on segment drivers b to g
        DisplayLED++;               // select next digit

        __delay_ms(10);             // Show digit for 10 milliseconds
        
        if(0 == PORTAbits.RA3)      // is SW1 pressed?
        {
            LoopCount++;
            if(LoopCount == 1)
            {
                // Display a new random value every 500 milliseconds
                Temp = rand() & 0xFFu;      // put random value in range of 0 to 255 and treat is as a fraction in range (0/256) <= value < (255/256)
                Temp = (Temp * 56u + 0x100u) >> 8; // Use tricky math to make a random number in the range from 1 to 56
                DisplayValue = (Temp / 10u) << 4;  // Extract the ten's digit
                DisplayValue = DisplayValue | (Temp % 10); // Extract the one's digit
            }
            if(LoopCount >= 50)
            {
                LoopCount = 0;
            }
        }
        else
        {
            LoopCount = 0;
        }

        if(0 == PORTAbits.RA4)      // is SW2 pressed?
        {
            DisplayValue = 0;       // Reset display value to zero
            LoopCount = 0;
        }
    }
}

这篇关于Pic16f684 &amp;双七段显示程序:C中的随机数生成器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆