I'm going to write a code with three cases(PINA first three ports as inputs and PORTB as outputs), One, toggle all led's connected to PORTB simultaneously with a period T1 when PINA.0 has went HIGH,Second toggle all led's one after one with a period T2... when PINA.1 went HIGH...
The problem is when ever an another input has went high the process should be stopped and switched to the corresponding input, can I use timers and interrupts for this goal?
... can I use timers and interrupts for this goal?
Answer is YES :)
Related
I'm in a strange situation with an ATMega2560.
I want to save power by going into PowerDown mode. In this mode there are only a few events only which can wake it up.
On USART1 I have an external controller which sends messages to the AVR.
But when USART1 is used I can not use the INT2 and INT3 for external interrupt (=the CPU will not wake up).
So I had an idea to disable the USART1 just right before going into PowerDown mode, and have the INT2 enabled as external interrupt.
Pseudo code for this:
UCSR1B &= ~(1<<RXEN1); //Disable RXEN1: let AVR releasing it
DDRD &= ~(1<<PD2); //Make sure PortD2 is an input - we need it for waking up
EIMSK &= ~(1<<INT2); //Disable INT2 - this needs to be done before changing ISC20 and ISC221
EICRA |= (1<<ISC20)|(1<<ISC21); //Rising edge on PortD2 will generate an interrupt and wake up the AVR from PowerDown
EIMSK |= (1<<INT2); //Now enable INT2
//Sleep routine
cli();
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
In the ISR of INT2, I change everything back to USART1.
Pseudo:
ISR(INT2_vect) {
EIMSK &= ~(1<<INT2); //Disable INT2 to be able to use it as USART1 again
UCSR1B=(1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1);
}
However it seems to take long time until the USART1 is working correctly again.
There are too many faulty bits in the beginning (after waking up from PowerDown).
How hackish is this?
Is there any reasonable way to make the change faster?
The main idea was to set the 'RX' port to an interrupt which can wake the CPU up then immediately change it back to USART and process it asap.
PS: I really have to use the same pin for this purpose, there is no other available option. So guiding toward using some other pins won't be accepted as an answer.
The Power-down mode disables the oscillator, so you have to wait for a stable oscillator after wakeup.
Please take a look at the datasheet on page 51:
When waking up from Power-down mode, there is a delay from the wake-up condition occurs until the wake-upbecomes effective. This allows the clock to restart and become stable after having been stopped. The wake-upperiod is defined by the same CKSEL Fuses that define the Reset Time-out period, as described in “ClockSources” on page 40.
You have to wait up to 258 clock cykles assuming you use a high speed ceramic oscillator (see table 10-4 on page 42).
You can use the Standby Mode. If you use an external oscillator the CPU enter the Standby Mode, which is identical to Power-down Mode, but the Oscillator isn´t stopped. Furthermore you can set the Power Reduction Register for additional power save options.
Another option is to use the Extended Standby Mode, which is identical to the Power-save Mode. This mode disables the oscillator, but the oscillator wakes up in six clock cycles.
I am using the internal oscillator (FOSC = 7.37 Mhz) of the dsPIC33EV256GM102. I have a 1602 LCD connected to the PIC via 4 data, and enable, RW, and RS control lines.
I write initialization commands to the LCD and then two lines of text. That works fine.
After 2 minutes and 10 seconds the enable line quickly pulses high-low causing something to be written to the LCD. It happens again in another 2:10 and then again, repeatably.
All my program does right now is initialize the LCD, write two lines of text and go directly into a while(1).
I have tried setting the LCD enable low on every iteration of the While. I have tried latching the enable low before going into the While. I have moved the enable to another pin but the pulse still occurs on that pin. If I remove the enable line after writing the data, the problem goes away.
Any thoughts what might cause this kind of behavior or what additional troubleshooting steps I might take?
I am using pin 24 labeled RPI45/PWM1L2/CTPLS/RB13 for the enable but I have also tried pin 23 labeled RPI44/PWM1H2/RB12. I am not executing any code related to peripheral pin select yet.
When I download the program via the Pickit3, for the first POR while the Pickit3 is still in the circuit, there is some spurious text written to the LCD. So I have to disconnect the Pickkit3 and do another POR before the two line of text are written correctly without any unwanted additional data writes.
In conclusion there are two issues really or perhaps they are related?
I began to study PIC assembly and I have one issue with PIC16F877 related with push buttons. Firstly, I show you configuration:
I want to check if SW04,SW05,SW06,SW06,SW11 are pressed, but I guess RB7 is responsible for SW07 and SW11. Will it cause problems, if I will only check for RB7, because in one function I must check SW07 and SW11 buttons.
No, it is not going to cause problems because when you check RB7 at certain moment of time you know for sure what line caused the signal: RB2 or RB1. If you register RB7 and RB1 is the active one, that means SW07 is pressed, if RB2 is active - then SW11 is pressed. I am assuming your program moves the logic '1' from RB0 to RB3 and every line has '1' at certain moment whilst others are Zeros.
No worries. Turning on pull-up resistors at RB4-RB7 inputs should not cause problems, it is just the determined state of input when it is in tri-state. These inputs should work well and normally see what RB0-RB3 outputs give them: '0' or '1'. By the way you can choose between two methods: when '0' moves among RB0-RB3 and others are '1', or when '1' moves around the RB0-RB3 among zeros. Depending on this you are scanning for '0' or for '1' respectively at RB4-RB7.
Is it possible to query serial port tx (send) pin status if it is active or not ?
For example when issuin break command (SetCommBreak) tx pin is set to active (low). I'd like to know when it is active or not. Thanks.
No. (at least not likely)
If you are using the "16550" family of UARTs, then I am confident that you can not query the serial port tx pin status. Of course, if you are using some new version or other UART family, maybe.
You can assume that the TX pin is in the SPACE state ('0', +Volts) whilst performing SetCommBreak(), but I suspect that is not enough for you.
If you are look to debug your code to know if a break occurred, you can short pins 2 & 3 on a 9-pin D-sub, thus loop backing the transmit to the receive. A paper clip will do. Your receive code would detect the incoming BREAK. Shorting to the incorrect pin does not cause a lasting problem with a conforming serial port, but be careful. Try this first with simple data, before testing BREAK condition.
If you have a "16550"-like UART.
You can put the UART into loop-back mode and see if you receiving you own outgoing BREAK signal. Its somewhat complicated in current PCs. Other UART type may support loop-back.
I'm supposed to write a program that will send some values to registers, then wait one second, then change the values. The thing is, I'm unable to find the instruction that will halt operations for one second.
How about setting up a timer interrupt ?
Some useful hints and code snippets in this Keil 8051 application note.
There is no such 'instruction'. There is however no doubt at least one hardware timer peripheral (the exact peripheral set depends on the exact part you are using). Get out the datasheet/user manual for the part you are using and figure out how to program the timer; you can then poll it or use interrupts. Typically you'd configure the timer to generate a periodic interrupt that then increments a counter variable.
Two things you must know about timer interrupts: Firstly, if your counter variable is greater than 8-bit, access to it will not be atomic, so outside of the interrupt context you must either temporarily disable interrupts to read it, or read it twice in succession with the same value to validate it. Secondly, the timer counter variable must be declared volatile to prevent the compiler optimising out access to it; this is true of all variables shared between interrupts and threads.
Another alternative is to use a low power 'sleep' mode if supported; you set up a timer to wake the processor after the desired period, and issue the necessary sleep instruction (this may be provided as an 'intrinsic' by your compiler, or you may be controlled by a peripheral register. This is general advice, not 8051 specific; I don't know if your part even supports a sleep mode.
Either way you need to wade through the part specific documentation. If you could tell us the exact part, you may get help with that.
A third solution is to use an 8051 specific RTOS kernel which will provide exactly the periodic delay function you are looking for, as well as multi-threading and IPC.
I would setup a timer so that it interrupts every 10ms. In that interrupt, increment a variable.
You will also need to write a function to disable interrupts and read that variable.
In your main program, you will read the timer variable and then wait until it is 10100 more than it is when you started.
Don't forget to watch out for the timer variable rolling over.