I tested this code for all four inboard LEDs and an external LED.
All LEDs turned ON, but they don't blink.
Here is my code:
#include "stm32f4xx.h"
void WaitaMoment (int time)
{
for (time = 0; time > 0; time--);
}
int main(void)
{
RCC -> AHB1ENR |= RCC_AHB1ENR_GPIODEN;
GPIOD -> MODER |= GPIO_MODER_MODER14_0;
GPIOD -> OTYPER &= ~ (GPIO_OTYPER_OT_14);
GPIOD -> OSPEEDR |= GPIO_OSPEEDER_OSPEEDR14;
GPIOD -> PUPDR &= ~ (GPIO_PUPDR_PUPDR14);
//int time;
while(1)
{
GPIOD -> BSRRL |= GPIO_BSRR_BS_14;
//for (time=0; time < 200000; time++);
WaitaMoment(200000);
GPIOD -> BSRRH |= GPIO_BSRR_BR_14;
WaitaMoment(200000);
//for (time=0; time < 200000; time++);
}
}
What is my problem?
The for loop in WaitaMoment does not iterate because it sets time = 0 and then loops while time > 0 which is never. Change it so that the loop does not set time = 0.
void WaitaMoment (int time)
{
for (; time > 0; time--);
}
This loop may still not iterate if the compiler recognizes that it doesn't do anything and optimizes it away. Make sure the delay is not getting optimized away or the LED may flash so fast that you cannot see the flashes.
As mentioned in the comments, you shouldn't use |= with BSRRL and BSRRH. Write it like this instead.
GPIOD->BSRRL = GPIO_BSRR_BS_14;
WaitaMoment(200000);
GPIOD->BSRRH = GPIO_BSRR_BS_14;
WaitaMoment(200000);
And make sure you have spelled everything correctly (GPIO_BSRR_BS_14 not GPIO_BSRR_BR_14)
Related
I am new to microcontroller. The following code measures the period of a square wave. I have marked some lines which I haven't understood. The code is as follows:
#include <avr/io.h>
#include <avr/interrupt.h>
ISR(TIMER1_CAPT_vect)
{
int counter_value = ICR1; //16 bit value
PORTB = (counter_value >> 7); // What has been done here?
TCNT1 = 0; // why this line?
}
int main(void)
{
DDRB = 0xFF;
TCCR1A = 0x00;
TCCR1B = 0b11000010;
TIMSK = 0b00100000;
sei();
while(1);
cli();
}
What has actually been done in those lines?
ISR(TIMER1_CAPT_vect)
{
int counter_value = ICR1; //16 bit value
PORTB = (counter_value >> 7); // What has been done here?
PORTB is a set of 8 output lines. Presumably, they are connected by a bus to some device you haven't mentioned. Maybe even a set of LEDS to display a binary number.
The result from the counter is 16 bits. To get the most significant bits, shift the result to the right to discard the less significant bits. (This operation loses precision, but you only have 8 bits of output, not 16.) As to why the shift is only 7 instead of 8, or why the unsigned value of the counter is saved as a signed int first, I don't know. I suspect it is a mistake. I would have done PORTB = (ICR1 >> 8); instead.
TCNT1 = 0; // why this line?
Since we have recorded the time of the capture and sent it out PORTB, we now want to reset the timer for the next capture.
}
I am well familiar with PWM generation in Atmega128 and its family microcontrollers. I have been using prescalar and other registers for generating frequency. But I have to generate 20KHz pwm signal. I tried but I could not get the desired output. Can anyone suggest me or help me how to do it ?
As far as I know, in atmega128, 1 instruction takes 1 cycle. Using 16MHz crystal, 1 instruction completes in 1/16M sec.
I tried to generate 20Khz signal (50 us)with 25us duty cycle. But I get different frequency (277.78 Hz) in oscilloscope which is far less than 20KHz
My calculation was
16MH = 20000Hz * 800.
for 0-399 count, I made port high and
399-799 count, I made port low.
void frequency(void){ // 20kHz Frequency
if (cnt1 <= 399){
PORTB |= (1<<7);
} else {
PORTB &= ~(1<<7);
}
cnt1++;
if (cnt1 >= 800) cnt1 = 0;
}
I don't have access to the 128 but verified its 16-bit Timer 1 is similar to that in the 328 and 32U4 so the following should work with minor modification (the main sticking point is probably looking up what pin the overflow register is bound to):
#include <avr/io.h>
#include <util/delay.h>
struct CTC1
{
static void setup()
{
// CTC mode with TOP-OCR1A
TCCR1A = 0;
TCCR1B = _BV(WGM12);
// toggle channel A on compare match
TCCR1A = (TCCR1A & ~(_BV(COM1A1) | _BV(COM1A0))) | _BV(COM1A0);
// set channel A bound pin PB1 to output mode
#if defined(__AVR_ATmega32U4__)
DDRB |= _BV(5);
#else
DDRB |= _BV(1);
#endif
}
static void set_freq(float f)
{
static const float f1 = min_freq(1), f8 = min_freq(8), f64 = min_freq(64), f256 = min_freq(256);
uint16_t n;
if (f >= f1) n = 1;
else if (f >= f8) n = 8;
else if (f >= f64) n = 64;
else if (f >= f256) n = 256;
else n = 1024;
prescale(n);
OCR1A = static_cast<uint16_t>(round(F_CPU / (2 * n * f) - 1));
}
static void prescale(uint16_t n)
{
uint8_t bits = 0;
switch (n)
{
case 1: bits = _BV(CS10); break;
case 8: bits = _BV(CS11); break;
case 64: bits = _BV(CS11) | _BV(CS10); break;
case 256: bits = _BV(CS12); break;
case 1024: bits = _BV(CS12) | _BV(CS10); break;
default: bits = 0;
}
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11) | _BV(CS10))) | bits;
}
static inline float min_freq(uint16_t n)
{
return ceil(F_CPU / (2 * n * 65536));
}
};
void setup()
{
CTC1::setup();
CTC1::set_freq(20e3);
}
void loop()
{
// do whatever
_delay_ms(1);
}
int main()
{
setup();
for (;;)
loop();
}
I tested on my scope and measure exactly 20kHz off a 328p running at 16MHz. If 20kHz is the only frequency you need then you can simplify this substantially. Translating the code to use one of the 8-bit timers is also straightforward though I haven't verified that it's possible to hit exactly 20kHz with those.
It's not a good idea to use counter in C to implement the PWM or anything time critical really. Although C converts your code to specific machine code, you don't really know how much time it will take.
Your code does not translate to:
make port B high 400 times (PORTB |= (1<<7);)
make port B low 400 times (PORTB &= ~(1<<7);)
, but rather something like this (simplification, human-readable):
load variable cnt1 to memA;
load 399 to memB
compare mem A to memB
put result to memC
if memC eq "somthing indicating <=" do PORTB |= (1<<7);
if memC something else do PORTB &= ~(1<<7);
load cnt1 to memD and increment;
write memD to cnt1;
load 800 to memE
load cnt1 to memF
compare memF to memE
put result to memG
if memG eq "somthing indicating <=" do memF = 0, write memF to cnt1;
if memG something else go to start;
If you look at this from "C" point of view you need to do at least:
1. comare cnt1-399
2. if ok - do / else
3. port high / port low
4. add one to cnt1
5. compare cnt1 and 800
It then depends on you compiler how good it is at optimizing all the loads and writes (usually quite good).
You can have control on what the delays will be if you really know your compiler and don't use to much optimization (it is usually to complex to follow) or by writing the code in assembler. But then you will have to use logic similar to my explanation of the machine code (assembler is close to human-readable machine code).
I think the solution for you are timer interrupts. There's a good tutorial for atmega128 this here.
Also what do you mean with:
I tried to generate 20Khz signal (50 us)with 25us duty cycle.
Do you mean 20kHz signal with 50% duty cycle? so 25us low, 25 us high?
If this is the case you can do this with one timer interrupt and one (binary) counter.
Exactly the "8 bit timer example" you can read about in the provided link.
I'm trying to use an arduino uno to show some students how to make their own 'auto tune' however the code that I wrote is not outputting any signal. The goal is to sample values into an array at one rate and output the data from the array(FIFO)at a slower rate. My understanding is that TCNT1 increments each clock tick, I'm using 16 MHz in my case, and that I can base if logic on the value of TCNT1, I use a mod function here to take and store a single adc value and then play that value to the dac at a later time. acdT dacT represent my timing logic. I've built an external DAC to read only 8 (of 10) bit values from d0-d7 (PORTD). Why am I not seeing a signal?
int i = 0;
int j = 0;
int adcT = 328; // 329 clock tics
int dacT = 349; // 350 clock tics
int buff[15]; // 16 length buffer to store adc values
void setup ()
{
PRR &= ~(1<<PRADC); //ADC turned on
ADMUX = 0x60; //AVcc, left adjusted, ADC0 pin
ADCSRA = 0xC0;//ADC Enabled, no auto trigger
DDRD=0xFF; // set portd to d0 thru d7 digital pins
DDRC=0x00; // accept input from any analog input
TCCR1B |= 1<<CS10; // sets the clock to the system clock ie no pre scaler
}
void loop ()
{
if((TCNT1%acdT == 0) || TCNT1 == 0) // execute at 0 and mod329 clock tics
{
ADCSRA|=(1<<ADSC); // take one adc reading
while(!(ADCSRA & (1<<ADIF))); // wait until the reading is complete
ADCSRA|=(1<<ADIF); //reset adc for next command
buff[i] = ADCH; // take the adc value into the array
i++ // increment
}
if((TCNT1%dacT == 0)) %% TCNT1 ~= 0// execute at mod350 clock tics
{
PORTD = buff[j]; // send the adc reading to digital output
j++;
}
if(TCNT1 == 5262 ) // LCM/3 of 329(16samples) and 350(15samples)
{
TCNT1 = 0;// reset ticker
i = 0;
j = 0;
}
if(TCNT1 == 336)
{
PORTD = buff[15]; // play 16th adc sample to clear array
}
}
TCCR1B |= 1<<CS10; // sets the clock to the system clock ie no pre scaler
And there's your problem. You're attempting to find the modulus of a counter that runs faster than your code. Use the output capture and other features of the timer to trigger interrupts and reset the timer at the appropriate times instead of trying to catch a passing bullet with your bare hands.
OK, so i have accomplished creating a software and hardware UART on PIC18f8680 in MikroC compiler. The Soft_Uart uses timer0 for interrupt and breaks the Soft_UART_read() line by a function called Soft_uart_Break().
everything is working fine, when i read a single character from both uart. but when i send a string on hardware uart, the string doesn't gets reads properly by these lines;
UART1_Read_Text(buffer, "OK", 100);
UART1_Write_Text(buffer);
I've found out whats causing this problem. that is, my main while loop gets stuck in Soft_UART_read() until it gets break by an interrupt. while its stuck over there, the hardware uart doesn't gets proper time to read the whole string, so as a result it displays some of the characters of that string.
how can i overcome this ? do i need to use a separate interrupt for hardware uart aswel ? or what ? any help would be highly appreciated.
here is a snip of my code;
void main() {
INTCON.GIE=1; //globle interrupt enable
INTCON.PEIE=1; //peripharel interrupt enable
INTCON.TMR0IF = 0x0; //Clear timer0 overflow interrupt flag
INTCON.TMR0IE = 1; //enable the timer0 by setting TRM0IE flag
T0CON.TMR0ON = 1; // Timer0 On/Off Control bit: 1=Enables Timer0 / 0=Stops Timer0
T0CON.T08BIT = 0; // Timer0 8-bit/16-bit Control bit: 1=8-bit timer/counter / 0=16-bit timer/counter
T0CON.T0CS = 0; // TMR0 Clock Source Select bit: 0=Internal Clock (CLKO) / 1=Transition on T0CKI pin
T0CON.T0SE = 0; // TMR0 Source Edge Select bit: 0=low/high / 1=high/low
T0CON.PSA = 1; // Prescaler Assignment bit: 0=Prescaler is assigned; 1=NOT assigned/bypassed
T0CON.T0PS2 = 0; // bits 2-0 PS2:PS0: Prescaler Select bits
T0CON.T0PS1 = 1;
T0CON.T0PS0 = 1;
TMR0H = 0xBD; // preset for Timer0 MSB register
TMR0L = 0xCD; // preset for Timer0 LSB register
while(1) {
data1 = Soft_UART_Read(&error);
Soft_UART_Write(data1);
if (data1 == 'b') {
for(x = 0; x <= strlen(alive); x++) {
Soft_UART_Write(alive[x]);
}
}
if (UART1_Data_Ready()) { // If data is received,
UART1_Read_Text(buffer, "OK", 100); // reads text until 'OK' is found
UART1_Write_Text(buffer); // sends back text
/*if (uart_rd == 'a') {
UART1_Write_Text("\rSensor 1 data\r");
}*/
//else
//UART1_Write(uart_rd); // and send data via UART
}
}
}
I had the same issue. Some of the example code and documentation in the MikroC manual seems to contradict itself.
The prototype is:
void UARTx_Read_Text(char *Output, char *Delimiter, char Attempts);
Your delimiter should be:
char delimit[] = "OK";
UART1_Read_Text(&dataIn,&delimit,attempts);
If you know the size of the data being received attempts should correspond to this.
Im trying to figure out how to dim a led over time(time is defined by the user lets call it rampUp). Im using arduino with the adafruit breakout PWM-Servo-Driver (http://www.adafruit.com/products/815) with the library : https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
this breakout has 4095 steps (0-4095) so now my problem:
I want to be able to take a variable ( int minutes) and send that to a method that will dim a LED from 0 to 4095 in a equal light intensity increase for the period minutes. I want the increase to be incremented by 1 each time it increases.
So how do I write the method without using delay() ?
void dimLights(int rampUp){
// some code to regulate the increase of the third value in setPWM one step at a time over a period of rampUp(int in minutes)
led.setPWM(0,0,4095);
}
the reason for not wanting to use delay() is because it will pause/stop the rest of the program.
I actually implemented something close recently:
void loop() {
/* ... */
if (rampUp != 0)
led.setPWM(0,0,rampUp);
}
void led_update() {
// here you can prescale even more by using something like
// if (++global_led_idx == limit) {
// global_led_idx = 0;
++rampUp;
}
void start() {
TCCR1B |= _BV(WGM12);
// set up timer with prescaler = FCPU/1024 = 16MHz/1024 ⇒ 60ms
TCCR1B |= _BV(CS12) | _BV(CS10);
TCCR1B &= ~_BV(CS11);
// initialize counter
OCR1A = 0x0000;
// enable global interrupts
sei();
// enable overflow interrupt
TIMSK1 |= _BV(OCIE1A);
}
void TAGByKO_LED::stop() {
TIMSK1 &= ~_BV(OCIE1A);
rampUp = 0;
}
ISR(TIMER1_COMPA_vect, ISR_NOBLOCK) {
led_update();
}
then you can call start() to start the timer, or stop() to stop it. You can read more documentation about the registers I've been using here and the ISR statement. Beware that it's one of the most tricky things of AVRs to really understand, and even then you'll always need to have a cheatsheet or the datasheet close by.
You may also use #sr-richie's solution with timers, but do only setup variables in the dimLights() function, and call led.setPWM() only within the loop().