Programming a 7 segment display based on push button [closed] - c

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
New to PIC programming or just programming in general. Wondering how I can display a number on the 7 segment display that corresponds to the number of times the push button at RA5 is pressed. E.g press button 2 times = number 2 displayed and if it's pressed 10 times, the count resets to 0. Any help is appreciated

What do you mean this question is too broad?
Tom, first off, to help you out in the future:
According to the "closed" info. box on the question, this question was closed because it "needs to be more focused", and it should be updated "so it focuses on one problem only." I'd like to help you know what that means from my perspective.
I didn't vote to close it, but in this case I totally understand why it was closed.
It's too broad. You showed no coding attempt whatsoever and you asked what you thought was a very focused question, but which actually is too broad because there is too much to cover here. With you writing no code whatsoever, the questions within your question might include the following:
How do you write C at all?
How do you set up a main() function?
What's a function?
What's a variable?
What's a signed vs unsigned variable?
How do you do bare-metal multi-tasking?
How do you program a PIC microcontroller?
What are hardware registers and how do you use them?
How do you configure pins as inputs vs outputs?
How do you read pin states?
How do you write to pins?
How do you do bitwise operations to set an entire output port (all pins to the display) all at once instead of one-at-a-time?
How does electricity work?
What does it mean to write a pin to output LOW vs ouput HIGH vs input?
What's a pullup resistor?
What's an LED array? How do you drive one?
Are the LEDs in the 7-segment display turned on by writing the pin to output HIGH or output LOW (ie: do we need to source from or sink to the pins to light up the LEDs)?
How do displays work and how do you control them?
I originally didn't see the circuit diagram until I edited the question to make the image show up, so I at first I also needed this information and thought we may need to cover the following:
Does the 7-segment display have its own on-board driver IC and require I2C, SPI, or asynchronous RS-232-style TTL logic level Serial commands to drive it instead?
How do displays work and how do you control them?
What is Persistence of Vision (PoV) and how might it apply?--in particular if driving multiple digits (multiple 7-segment displays)
Do we need to consider multiplexing so you can control more 7-Segment digits with fewer pins?
Do we need to consider Charlieplexing to use fewer pins still than standard multiplexing?
Anyway, let me get you started. The concept for your circuit is pretty straightforward.
Here is how your circuit works:
Each segment on the display is turned on by setting the appropriate pin to output LOW, since Vcc (probably 5V) is connected to the other side of the LEDs. So, to turn on segment a, you'd set RC0 to output LOW, to turn on segment b, you'd set RC1 to output LOW, etc. Since all of your LEDs in this display share a common Vcc (usually 5V) pin, this is a common anode 7-segment display. Since each of the 7 LEDs in the display has its own dedicated pin, you can light up any of the LEDs at one time, rather than having to round-robbin through them in a multiplexed or Charliplexed fashion.
If you wish to add another digit (another 7-segment display), you can double the number of required pins from 7 to 14, OR you can multiplex the new display, moving Vcc of each display to its own pin, and sharing the 7 segment pins RC0 through RE2. Therefore, 2 displays can take 14 pins if not multiplexed, or 9 pins if multiplexed. OR, if you have a common-anode and a common-cathode 7-segment display, you can Charlieplex them, hooking up each individual LED together and the common anode of one display and the common cathode of the other display together on another pin, thereby getting away with only 8 pins for 2 displays--the direction of current would set which display gets lit up. Round-robbining through the displays to refresh them, thereby relying on our eyes' persistence of vision trait, would be required for both multiplexing and Charlieplexing.
You read the RA5 button presses by seeing when RA5, an input pin, goes LOW. Since the button grounds the pin, and the pin has an external pullup resistor on it, HIGH means the button is NOT pressed, and LOW means it is pressed. Be sure to debounce this button press in software or else a single button press may register as dozens or even hundreds of button presses, depending on the mechanics of the button.
That's the circuit.
Here is how the program logic works:
The logic is pretty straightforward too: each time you read a debounced button press, increment a counter. Output the digit on the 7-segment display according to the counter. Example: to write a 2, you'd turn on segments a, b, g, e, and d. You can look at the display to figure out the other numbers.
Sample source code outline to get you started:
#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h> // For `uint8_t`, `int8_t`, etc.
// Read the pin to look for button presses and return true if the
// **debounced** button changes indicate the button has been pressed once
bool buttonWasPressedOnce()
{
// you do this
}
// Write a number 0 to 9 to the display
void writeDisplay(uint8_t number)
{
// you do this
}
// set up your PIC peripherals, input/output pin states, etc, here
void setup()
{
// you do this
}
// your main program logic goes here; this runs repeatedly, forever
void loop()
{
static uint8_t button_pressed_count = 0;
if (buttonWasPressedOnce())
{
button_pressed_count++;
// roll over after 9 back to 0
if (button_pressed_count > 9)
{
button_pressed_count = 0;
}
}
writeDisplay(button_pressed_count);
}
int main()
{
setup();
while (true)
{
loop();
}
return 0;
}
References and additional reading, including sample libraries to look at:
Here is some Arduino code to get you started, to see various options. Port it to your PIC microcontroller: https://www.instructables.com/Different-methods-of-driving-7-Segment-LED-display/
Sample library to study as a reference: https://github.com/DeanIsMe/SevSeg
You'll also need to know button debouncing, and a ton of other skills. Example debouncing: https://www.arduino.cc/en/Tutorial/BuiltInExamples/Debounce
my own debounce library I wrote for Arduino a long time ago: https://www.electricrcaircraftguy.com/2014/05/ercaguybuttonreader-library-for-arduino.html and https://github.com/ElectricRCAircraftGuy/eRCaGuy_ButtonReader and https://github.com/ElectricRCAircraftGuy/eRCaGuy_EventReader
https://www.allaboutcircuits.com/technical-articles/driving-led-arrays-with-an-arduino/
https://www.google.com/search?q=led+array&oq=led+array&aqs=chrome..69i57j69i65.2207j0j7&sourceid=chrome&ie=UTF-8
https://www.sparkfun.com/products/retired/13795
great video: https://www.youtube.com/watch?v=ohewJ9sTfwM
https://en.wikipedia.org/wiki/Multiplexed_display
https://en.wikipedia.org/wiki/Charlieplexing
https://en.wikipedia.org/wiki/Three-state_logic
https://en.wikipedia.org/wiki/Persistence_of_vision
https://en.wikipedia.org/wiki/Seven-segment_display

Related

Timing functions on the MSP430FR6989 in C

For a project I want to time how long a function takes. For this, I was thinking of using TimerA TA0 and a capture. However, after looking through the documentation, I was wondering if it is possible to capture the timer using an internal "message". In the datasheet (http://www.ti.com/lit/ds/symlink/msp430fr6989.pdf page 87, table at the bottom of the page) it is not really clear to me how to do this. It states the Port pins which can be used, but I am (obviously) not interested in that.
I was thus thinking if I was able to write to the TAxIV regitser, to just set the interrupt flag myself, but I'm absolutely not sure if it would work (I don't really think so, but I don't know why), I could use that to capture the timer.
I also already looked at the example code, but there they use ACLK to as an input signal. So that is not of much use either.
With kind regards and thanks in advance
As shown in the Timer_A block diagram (figure 25-1) in the User's Guide, the capture signal must come from one of the four capture inputs.
The last two inputs are always connected to GND and VCC, so you can trigger the capture manually by switching between these two inputs (see section 25.2.4.1.1).
The answer is (all thanks go to CL. ,see above, who gave the answer):
for initialisations:
TA0CCTL1 = CM_3 | CCIS_1 | SCS | CAP; // could put in interrupt here
TA0CTL = TASSEL__SMCLK | MC__CONTINUOUS; // setting the timer up with the SMCLK
and for usage, meaning capturing the timer:
TA0CCTL1 ^= CCIS0 // TA0CCR1 = TA0R, toggling the CCIS0 bit to switch between Vcc and GND
and then just reading the capture register out.
This answer is here to make it easier to read, for the full answer see my conversation with CL. above, whom gave me the answer.

Control WVGA display with stm32f429-discovery LTDC

I am trying to output some data on the 7 inch TFT-LCD display (MCT070PC12W800480LML) using LCD-TFT display controller (LTDC 18 bits) on STM32F4.
LTDC interface setting are configured in CubeMx. In the program lcd data buffer is created with some values and it's starting address is mapped to the LTDC frame buffer start address.
At this moment display doesn't react to data sent by the LTDC. It only shows white and black strips, after i connect ground and power for digital circuit to the 3 volts source. VLED+ is connected to the 9 volts source. The VSYNC, HSYNC and CLOCK signals are generated by the LTDC and they match with specified values. I measured them on LCD strip, so the connection should be right. I also tried putting pulse on the LCD reset pin, but that doesn't make any sense.
The timing setting might be wrong.
LTDC clock is 33 MHz.
Here is the link to the diplay datasheet http://www.farnell.com/datasheets/2151568.pdf?_ga=2.128714188.1569403307.1506674811-10787525.1500902348 I saw some other WVGA displays using the same timing for synchronization signals, so i assume that timings are standard for that kind of displays.
Maybe signal polarity is wrong or i am missing something else. The program i am using now, worked on stm32f429-discovery build in LCD i just changed the timings. Any suggestions?
Thank you.
It could be something else, but I can see a problem with your timing values.
The back porch for both horizontal and vertical includes the sync pulses, but there must be a sync pulse width. My observation is that you have tried to get the total clocks for h = 1056 and v = 525 as per the data sheet by setting the sync pulses to 0. That won't work.
I would make the hsync pulse 20 and vysnc 10. The total clocks will be the same, but it is not critical that they match the spec sheet.

STM32 - TIM2_ETR pin, connected to pin PA0 (button), incrementing the timer in strange way

I am trying to implement PWM LED dimming in 6 stages, where each stage in more bright, based on clicking button, which increments external pin, which serves the value to timer.
I am facing a problem, that sometimes, value variable is too large than it should be and skips some levels of brightness. For example, value increments: 1,2,3, then jumps to 6,7, etc.
Can anybody pinpoint where is the mistake I am making.
Here is the code:
//EDIT: code removed, because it is a school assignment
This looks like contact bouncing. When input is processed by the CPU, a simple way to solve it is to disable input for a certain duration after an event is detected. Since you directly control timer input from a button, you may not have much control. However, I would experiment with the ETF field of the SMCR register (which in your case is likely set by the sClockSourceConfig.ClockFilter field) and the clock divisor CKD of the CR1 register (which seems like htim2.Init.ClockDivision in your code) (sorry, I am not familiar with STM libraries).

Push a button while reading sensor in Arduino

I've been doing a little thermometer project to learn Arduino and there is an annoying thing that I have no idea how to resolve.
I have two push buttons to set Min and Max temperature and when I push the buttons it's supposed to set the Min and Max temperature on display.
The problem is that sometimes (50% of times) when I push the buttons during the reading of the temperature sensor, the buttons don't work. I press it but the Min/Max temperature are not set because Arduino is stuck in reading the temperature sensor.
Is there any trick to solve this kind of problem? If I had a keyboard for typing some number for example I imagine I would have the same problem and It's not "user-friendly".
Here is an example of part of the code I'm using:
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>
//variables declaration...
void setup() {
sensors.begin();
sensors.getAddress(sensor1, 0);
pinMode(buzzer, OUTPUT);
pinMode(btBuzzer, INPUT);
pinMode(btMin, INPUT);
pinMode(btMax, INPUT);
}
void loop() {
readButtons();
playBuzzer();
readTemperature();
printDisplay();
delay(150);
}
void readButtons(){
if(digitalRead(btBuzzer)){
buzzerOn = !buzzerOn;
}
if(digitalRead(btMin)){
if(tempMin == 69)
tempMin = 59;
else
tempMin++;
}
if(digitalRead(btMax)){
if(tempMax == 75)
tempMax = 63;
else
tempMax++;
}
}
void readTemperature(){
sensors.requestTemperatures();
temperature = sensors.getTempC(sensor1);
}
//lots of other methods
As others have pointed out here, the button press may not happen at the same time as you query the pin with digitalRead(btBuzzer). This type of problem is what so called "interrupts" were invented for, which allow you to respond to events that may occur while you are not monitoring the pin of interest.
For example, the Arduino UNO R3 allow for interrupts on pin 2 and 3. You should look up the reference for attachInterrupt(). The processor will execute a callback function in the event (the "interrupt") that you register for (e.g. the voltage on pin 2 changing from low to high). This means that you will no longer have to call a readButtons() function from your main loop.
Some of the best ways to learn coding exist in how to answer this question.
What I'd like to suggest doing is to try timing your code. Remember that loop() is creating a repeating structure. So we can say things like how long does the computer take to run each loop. When we have an interrupt like a button press how does that effect the iteration through the loop and is it conditional about how to rest the processor (the delay).
The delay is required so as to not do what's called "spin" the processor (have the processor as quickly as it can do a lot of work to accomplish absolutely nothing). However, notice how the code doesn't account for work done changing how long we delay?
Now let's imagine the processor actually can go through that loop more than one time very quickly. Remember delay of only 150 milliseconds isn't a lot of time. So maybe one button press will be enough to set tempMin from 59 to 69 in rapid succession and loop several times over rather than just increasing one number at a time.
What you have here is a chance to learn debugging. First trick is to determine is the loop running too fast or too slow; are you getting desired functionality or not and finally if you can reask the question after you know if it's happening too fast or slow.
For now, I'd recommend taking a look at global variables and finite state machines (i.e. if you're in a state of button press, don't accept any further button presses until you're done with your state and only transition in known ways).

Produce tones at certain time-interval using C programming

Im using C language for a PIC18F to produce tones such that each of them plays at certain time-interval. I used PWM to produce a tone. But I don't know how to create the intervals. Here is my attempt.
#pragma code //
void main (void)
{
int i=0;
// set internal oscillator to 1MHz
//OSCCON = 0b10110110; // IRCFx = 101
//OSCTUNEbits.PLLEN = 0; //PLL disabled
TRISDbits.TRISD7 = 0;
T2CON = 0b00000101; //timer2 on
PR2 = 240;
CCPR1L = 0x78;
CCP1CON= 0b01001100;
LATDbits.LATD7=0;
Delay1KTCYx(1000);
while(1);
}
When I'm doing embedded programming, I find it extremely useful to add comments explaining exactly what I'm intending when I'm set configuration registers. That way I don't have to go back to the data sheets to figure out what 0x01001010 does when I'm trying to grok the code the next time I have to change it. (Just be sure to keep the comments in sync with the changes).
From what I can decode, it looks like you've got the PWM registers set up, but no way to change the frequency at your desired intervals. There are a few ways to do it, here are 2 ideas:
You could read a timer on startup, add the desired interval to get a target time, and poll the timer in the while loop. When the timer hits the target, set a new PWM duty cycle, and add the next interval to your target time. This will work fine, until you need to start doing other things in the background loop.
You could set timer0's count to 0xFFFF-interval, and set it to interrupt on rollover. In the ISR, set the new PWM duty cycle, and reset timer0 count to the next interval.
One common way of controlling timing in embedded processes looks like this:
int flag=0;
void main()
{
setup_interrupt(); //schedule interrupt for desired time.
while (1)
{
if (flag)
{
update_something();
flag = 0;
}
}
Where does flag get set? In the interrupt handler:
void InterruptHandler()
{
flag = 1;
acknowledge_interupt_reg = 0;
}
You've got all the pieces in your example, you just need to put them together in the right places. In your case, update_something() would update the PWM. The logic would look like: "If it's on, turn it off; else turn it on. Update the tone (duty cycle) if desired"
There should be no need for additional delays or pauses in the main while loop. The goal is that it just runs over and over again, waiting for something to do. If the program needs to do something else at a different rate, you can add another flag, which is triggered completely independently, and the timing of the two tasks won't interfere with each other.
EDIT:
I'm now confused about what you are trying to accomplish. Do you want a series of pulses of the same tone (on-off-on-off)? Or do you want a series of different notes without pauses (do-re-me-fa-...)? I had been assuming the latter, but now I'm not sure.
After seeing your updated code, I'm not sure exactly how your system is configured, so I'm just going to ask some questions I hope are helpful.
Is the PWM part working? Do you get the initial tone? I'm assuming yes.
Does your hardware have some sort of clock pulse hooked up to the RA4/T0CKI pin? If not, you need T0 to be clock mode, not counter mode.
Is the interrupt being called? You are setting INT0IE, which enables the external interrupt, not the timer interrupt
What interval do you want between tone updates? Right now, you are getting 0xFFFF / (clock_freq/8) You need to set the TMR0H/L registers if you want something different.
What's on LATD7? and why are you clearing it? Are you saying it enables PWM output?
Why the call to Delay()? The timer itself should be providing the needed delay. There seems to be a disconnect about how to do timing. I'll expand my other answer
Where are you trying to change the PWM frequency? Don't you need to write to PR2? You will need to give it a different value for every different tone.
"Halting build on first failure as requested."
This just says you have some syntax error, without showing us the error report, we can't really help.
In Windows you can use the Beep function in kernel32:
[DllImport("kernel32.dll")]
private static extern bool Beep(int frequency, int duration);

Resources