I'm writing a firmware for an ATMega328 and facing some issues. After searching in my logic for hours I could boil the code down to the most basic example and still have the problem.
I'm setting a pin to the value of a variable. Because I don't want to store to copies of a big array I'm setting the pin to the same value over and over again and if the variable changes, the pin gets set to a different state.
int main() {
DDRB |= _BV(PB2);
while (1) {
PINB |= _BV(PB2);
_delay_ms(50);
}
return 0;
}
The problem is that with this code the pin toggles on and off every 50ms.
I could think of restructuring my code so I can detect change of the mentioned variable without the need of a copy.
But in the end I don't understand the problem, because I'm setting a bit of the output port to the same value over and over again.
PINB is input register (output register is PORTB).
And yes, writing 1 to input register PINx toggle bit in corresponding output register PORTx and pin value in modern (almost all for now) AVRs.
Related
for a prototype we need to have a hardware switch (e.g., a momentary pushbutton) trigger the taking of a screenshot on a PC and save it to file. Writing some windows software to take a screenshot and save it is trivial, the slightly trickier part is how to get an electrical signal (we can choose the voltage, and provide power as necessary) to the software. We absolutely want to keep this simple (i.e., no labview or anything) and reliable as possible. I see small module boxes such as this
https://labjack.com/products/u3?gclid=EAIaIQobChMI-MXkjcbB2gIVxVYNCh3C6AODEAQYAiABEgK_OvD_BwE
available, but are there even simpler solutions? I'm thinking of (but haven't taken the time to test) possibly a parallel-port-to-USB converter (which would be similar to the more common RS232-to-USB converter but may allow detection of individual high/lows(just a guess, never worked with a parallel driver from windows)), or something like that. Just querying for ideas before I spend time buying things and testing. Thanks!
This can be easily done with an Arduino Leonardo, Micro, and Due module. This page has an example very similar to your project:
// use this option for OSX:
char ctrlKey = KEY_LEFT_GUI;
// use this option for Windows and Linux:
// char ctrlKey = KEY_LEFT_CTRL;
void setup() {
// make pin 2 an input and turn on the
// pullup resistor so it goes high unless
// connected to ground:
pinMode(2, INPUT_PULLUP);
// initialize control over the keyboard:
Keyboard.begin();
}
void loop() {
while (digitalRead(2) == HIGH) {
// do nothing until pin 2 goes low
delay(500);
}
delay(1000);
// new document:
Keyboard.press(ctrlKey);
Keyboard.press('n');
delay(100);
Keyboard.releaseAll();
// wait for new window to open:
delay(1000);
}
I have little problems implementing a dither function to upgrade the PWM resolution of my ATmega88 and the leds it's controlling.
My thought was, to use a "kind of" floating number, consisting of two uint8_t as "decimal places" so that e.g. "255.31" would be represented by "0xff.0x1f" (BYTE_HIGH.BYTE_LOW).
Now I want the value in the OCR to dither between BYTE_HIGH and BYTE_HIGH+1 and for this I need a second counter (besides the timer itself) to generate an overlayed dutycycle (the duty cycle of the timer has to be incremented after (int) 255-BYTE_LOW cycles). But managing this stuff in the main() results in flicker and so I'd like to do this in an ISR called on timer overflow.
My avr is running at 20 MHz and to get a sufficient dither frequency I cannot use a prescaler higher than 8. Do you think, I might be calling the ISR too frequently? But there is not too much code in the ISR, though.
Another problem I could think of is, that the ISR has to write the OCR which might be read by the timer at the same time, but isn't this kind of "thread save" as the timer does never write to OCR?
I have not found anything concerning my problem appropriately and so I hope to get some hints. See my code below
#include <avr/interrupt.h>
#include <avr/io.h>
#define compare_register OCR2B //duty cycle
volatile uint8_t dither_count=0;
volatile uint8_t BYTE_HIGH=0;
volatile uint8_t BYTE_LOW=0;
void init_pwm(void){
//some standard pwm initializations
TCCR2A |= (1 << COM2A1);
TCCR2A |= (1 << COM2B1);
// non inverting, fast PWM mode and prescaler to
TCCR2A |= (0 << WGM21) | (1 << WGM20);
TCCR2B |= (1 << CS21);
// set desired pin as an output (not sure, if it's the correct pin, because I left out other pins in use)
DDRD = (1 << DDD3)|(1<<DDD4);
// enable interrupt on timer overflow
TIMSK2 |= (1<<TOIE2);
// enable global interrupts
sei();
}
ISR(TIMER2_OVF_vect){
dither_count++;
if(dither_count<=BYTE_LOW){
compare_register=BYTE_HIGH+1;
}else{
compare_register=BYTE_HIGH;
}
}
int main(){
init_pwm();
//this or any function dimming the leds
BYTE_HIGH=10;
BYTE_LOW=1;
}
This theoretically should work, but unfortunately it doesn't work in real. The ISR gets called, but does not act as desired. Do I call the variables correctly inside of the ISR?
I would be glad if someone would see a fundamental misstake I did, especially because I do not have any serial interface working for debugging...
Edit: meanwhile I found out, that obiously the ISR gets stuck and will block any code executed in my main function...
I tried your program on an Arduino Uno. This board is based on a
ATmega328P which, save for some extra memory, is basically the same as
your Mega88 (same datasheet). I first added the following lines at the
end of main():
init_pwm();
// Blink the LED on PB5.
DDRB |= _BV(PB5);
for (;;) {
PINB |= _BV(PB5);
_delay_ms(400);
}
The first line is obviously needed for the PWM to work. The LED blinking
is just a test to see whether the program gets stuck in the ISR or not.
The result is: it does not. The LED blinks just as expected. The PWM
output looks also OK on the scope. Notice that, contrary to what the
comment in the code says, you are configuring the timer in phase
correct PWM mode, not in fast PWM. The timer period is then 2×255 timer
clock cycles instead of 256.
I disassembled the binary and tried to count the number of CPU cycles
needed to service the interrupt. With the program compiled at the -Os
optimization level, I got about 50. Given that the interrupt fires every
2×255×8 = 4080 cycles, that's about 1.2% of the CPU power
spent servicing the interrupt.
im producing 100 remote controls using pic16f1823 and i need unique id for each remote but it should be constant over time so i think its better to generate a random before programming in mplab compiler and then compile these 100 remotes
i want not to change the remote_id manually
#include "mcc_generated_files/mcc.h"
#define remote_id 33800
char col;
uint24_t data_out;
void Reset_state(void);
int Key(void);
int Key_prime(void);
void main(void)
{...
please help me in this problem
It should be possible to use SQTP mode with the IPE as described here.
http://microchipdeveloper.com/ipe:serial-quick-turn-programming-sqtp-settings
Can you have a script in production that alters the ihex file so
that your serial number would appear different in EEPROM (EE) as most pics have 1k of internal EE for data storage ?
Then the remote would read its unique serial number from EE locations.
This would be a simple job for `gawk' say...
Use the SQTP functionality in the MPLAB IPE. You need to enter 'advanced mode' and sign into the IPE first.
In the SQTP tab, set it to save the values in EEPROM, as 'Raw Data', at memory address 0x00. Press 'Generate' and it will write an sqtp file for you.
Select the SQTP file in the 'operate' tab, under the field where you select your .hex file.
Every time you flash a new mcu, the IPE will increment to the next value in the SQTP file, and will even keep track between sessions.
you can use this in your code to retrieve the data:
unsigned char EEPROM_ReadByte(unsigned char eepromAddress)
{
while(RD || WR); // check the WR&RD bit to see if a RD/WR is in progress
EEADR=eepromAddress; // Write the address to EEADR.
RD = 1; // Set the RD bit to trigger the eeprom read operation.
return(EEDATA); // Return the data read form eeprom.
}
Call EEPROM_ReadByte, passing in 0x00, and it will return one char from your data. Increment eepromAddress and it will return the second char, etc.
Note that your data will be in reverse order, I am not sure why, it is perhaps due to the way SQTP files are encoded.
I connect PORTC.3 with switch to 5v. in my code I do some thing in conditional block "if(PORTC.3)".in proteus I change state of switch but every time PORTC.3 is 0! what does event occur?
thanks...
You will need to query the PIN register, specifically PINC.3 for you. Each port has one of these registers and it stores the input data of the pin.
Make sure your pins are set as input at the Data-Direction Register (DDR), in your case DDRC and you will need to set them low (logic 0) for them to be configured as an input.
I've got a STM32L-Discovery Board, which has got a STM32L152R8 microprocessor. I'm quite stuck trying to make basic things work.
I've looked the examples given by ST (the current consumption touch sensor and the temperature sensor), and I think they aren't user-friendly, with so many libraries, sub-processes and interrupts, that make the code really difficult to understand.
I've tried to turn on the blue LED (GPIO PB6), but I can't manage to do that.
My code compiles correctly but does nothing to the board. This is the code of "main.c".
RCC->AHBRSTR = 0x00000002;
RCC->AHBRSTR = 0x00000000;
RCC->AHBENR = 0x00000002;
GPIOB->MODER = 0x00001000;
GPIOB->OTYPER = 0x00000040;
GPIOB->OSPEEDR = 0x00001000;
GPIOB->PUPDR = 0x00000000;
GPIOB->ODR = 0x00000040;
while(1) {}
Am I missing something? Could I find really basic examples somewhere?
Thanks in advance!
The standard peripheral library that ST supplies on their website is a good starting point. It has examples on programming a GPIO. Note that their code is absolutely horrible, but at least it works and is something to start with.
What compiler/debugger are you using? If you are using IAR, then you can view the GPIO registers while stepping thru the code. Please post the values of the GPIO registers to your question and maybe we can help.
RCC->AHBENR = 0x00000002;
Change to "RCC->AHBENR |= 0x00000002;"
This will ensure you enable GPIOB without disabling everything else. The existing code will disabled important things like the flash memory controller and all the other GPIOs.
GPIOB->MODER = 0x00001000;
// This will set pin 6 as output, and all other pins as input. Was this your intent?
Change to "GPIOB->MODER = (GPIOB->MODER & 0xFFFFDFFF ) | 0x00001000;"
This will set pin 6 as an output without changing the configuration of any other pins.
GPIOB->OTYPER = 0x00000040;
// This will set the output type as open drain, meaning you can only pull the line down.
Change to "GPIOB->OTYPER |= 0x00000040;"
Set output as push-pull instead of open drain. You later code attempts to set this line high which will not work as an open drain output will pull to ground or allow the line to float. A push-pull output will allow you to set the line high or low.