问题
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.
I know in some respect, I can use rand() to choose.
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
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.
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();
}
}
}
回答1:
@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.
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.
The code avoids the Read-Modify-Write(RMW) trap for new players by only using 8-bit writes to the PORTA and PORTC registers.
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;
}
}
}
回答2:
Your digits are BCD coded(BinaryCodedDecimal), each digit 0-9 is coded in four bits 0000-1001.
DisplayLED
toggles between 0 and 1, to select which digit to display, you must ensure you don't update the random value until it have been displayed, actually you should probably update it even more seldom as the display relays on the after glow in the LED and our slow eyes to display an image.
if (DisplayLED == 0) {
uint8_t r = myrand(); // place your favorite random generator here.
DisplayValue = (r/10)<<4|(r%10);
}
Pin 0 and 1 on PortA are flipped by turning them to input and output respectively
TRISA = TRISA ^ 0b000011; // Swap Left/Right (RA0 and RA1)
PORTA = PORTA & 0b111100; // Make Sure Bits are Low
DisplayLED = DisplayLED ^ 1; // Other Digit Next
Since the least significant bits in TRISA
are initiated as 01
they will alternate when negated only one of them is always an output.
来源:https://stackoverflow.com/questions/63006839/pic16f684-dual-seven-seg-display-program-random-number-generator-in-c