I am using LPCXpresso1549 to generate chirp signal with frequency between 35000 Hz and 45000 Hz. First off, I generate DAC chirp samples on matlab, and store them in const uint16_t chirpData[]. The samples frequency is 96000 Hz, therefore 96001 samples. Then, I set the timer to send samples out one by one every (1/96000) second. However, my signal I got having frequency between 3200 Hz to 44000 Hz. Is that because the timer is slow?
enter code here
const uint16_t chirpData[NUM_SAMPLES] = { 2048, ...., 1728, 2048} //96001 sampels
#include "mbed.h"
#include "chirp.h"
Serial pc(USBTX, USBRX);
Timer t;
AnalogOut aout(P0_12);
int main()
{
int i = 0;
while(true) {
// Write the sample to the analog
t.start(); //start timer
if(t.read() >= 0.00001){ // 1/samplef = 0.00001
aout.write_u16(chirpData[i]);
i++;
t.reset(); // reset timer to zero
if(i > 96000) {
i = 0;
}
}
}
}
In this case I recommend you using Threads executing Tasks by:
#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )
xTaskHandle taskHandle;
xTaskCreate(..); //Check Task.h
Then you can set your task cycle by
void your_task() {
unsigned task_cycle_ms = 1/freq; //Careful, convert to ms.
portTickType xLastWakeTime = 0;
portTickType xFrequency = task_cycle_ms/portTICK_RATE_MS;
for(;;) {
vTaskDelayUntil( &xLastWakeTime, xFrequency );
//your code to execute every cycle here
}
}
Related
I'm working on a Distance measurement program using an AVR microcontroller. I use a 16x2 LCD and an ultrasonic sensor along with ATMEGA32A. I wrote a code to display the distance from the Ultrasonic HC-SR04 on the LCD screen, but it gives me false readings, it increases the distance when the object is very near and vice versa. I just want an accurate reading.
Ultrasonic datasheet
ATMEGA32A Datasheet
#include <avr/io.h>
#include <avr/interrupt.h>
#include <MrLcd/MrLCDmega32.h>
#define F_CPU 1000000
#include <util/delay.h>
#include <stdlib.h>
#define Trigger_pin PD0 /* Trigger pin */
static volatile int pulse = 0;
static volatile int i = 0;
int main(void)
{
Initialise();
DDRD = 0b11111011;
_delay_ms(50);
GICR |= 1<<INT0;
MCUCR |= 1<<ISC00;
int16_t count_a = 0;
char show_a[16];
sei();
while(1)
{
PORTD |= (1<<Trigger_pin);
_delay_us(10);
PORTD &= ~(1<<Trigger_pin);
count_a = pulse/58;
Send_A_String("Distance Sensor");
GoToMrLCDLocation(1,2);
Send_A_String("Distance=");
itoa(count_a,show_a,10);
Send_A_String(show_a);
Send_A_String(" ");
GoToMrLCDLocation(13,2);
Send_A_String("cm");
GoToMrLCDLocation(1,1);
}
}
ISR(INT0_vect)
{
if(i == 1)
{
TCCR1B = 0;
pulse = TCNT1;
TCNT1 = 0;
i = 0;
}
if(i==0)
{
TCCR1B |= 1<<CS10;
i = 1;
}
}
I tried to change the trigger pin definition and define it in the code itself but still no progress.
Update: I changed a bit more in the code but I'm getting hex values when the distance is more than 9, for example, 10 is being displayed as 1e.
This is for initialise function
void Initialise(void)
{
DataDir_MrLCDsControl|=1<<LightSwitch|1<<ReadWrite|1<<BipolarMood; //these information will go towards the LCD
_delay_ms(15); // Wait for the LCD to start
Send_A_Command(0x01); // to clear the screen
_delay_ms(2);
Send_A_Command(0x38); // TO tell LCD about 8 data lines
_delay_us(50);
Send_A_Command(0b00001110); //Some cursor command
_delay_us(50);
}
You are sending pulses at a very rapid rate (determined solely by the display update time), and they are asynchronous to the time/counter reset. You have no idea which pulse triggered the interrupt and it did not start at the same time as the timer.
I would suggest that you reset the counter at the start of the pulse, and capture the counter value on interrupt. When the time has exceeded the maximum range, send a new pulse:
First define some constants:
#define PULSES_PER_CMx100 (F_CPU * 100 / 68600)
#define MAX_RANGE_CM 300
#define MAX_RANGE_COUNT ((MAX_RANGE_CM * PULSES_PER_CMx100) / 100)
Then your measure/display loop might look like:
pulse = 1 ; // dummy start
GICR &= ~(1<<INT0) ; // Disable INT0
for(;;)
{
// Ready for new measurement?...
if( pulse != 0 )
{
// Send pulse and reset timer
PORTD |= (1<<Trigger_pin) ;
pulse = 0 ;
TCNT1 = 0 ;
_delay_us(10);
PORTD &= ~(1<<Trigger_pin) ;
// Wait for echo pulse interrupt...
GIFR |= 1<<INTF0; // Clear INT0 pending flag
GICR |= 1<<INT0 ; // Enable INT0
}
else // When measurement available...
{
int distance_cm = pulse * 100 / PULSES_PER_CMx100 ;
// display distance
...
}
// If out of range, timeout, send a new pulse
if( TCNT1 > MAX_RANGE_COUNT )
{
// Force a new pulse to be triggered
pulse = 1 ;
}
}
And the ISR:
ISR(INT0_vect)
{
pulse = TCNT1; // Capture time on interrupt
GICR &= ~(1<<INT0) ; // Disable further interrupts
}
Now bear in mind that that method will take measurements as fast as possible and since you are displaying them for human reading, that is rather unnecessary. You might simply put a delay in the loop - making the pulse timeout unnecessary, or better you could take the mean of multiple measurements to get a more robust measurement, or use a moving average window, with outlier rejection.
I am using a NUCLEO-L476RG development board,
I am learning to write GPIO drivers for STM32 family
I have implementing a simple logic in which I need to turn on an LED when a push button is pressed.
I have a strange issue:
Edit 1:The Bread board LED turns ON when the line temp=10 is commented, it doesn't turn ON when the delay issue called. Assuming if I add any line of code into that while loop the LED does not turn ON
The Bread board LED turns ON when the delay() function is commented, it doesn't turn ON when the delay issue called.
What could be the issue?
I have powered the board using the mini usb connector on the board, and the clock is configured at MSI with 4MHz
#define delay() for(uint32_t i=0; i<=50000; i++);
int main(void)
{
GPIO_Handle_t NucleoUserLED,NucleoUserPB,BreadBoardLED,BreadBoardPB;
uint8_t inputVal,BBinpVal;
uint32_t temp;
//User green led in the nucleo board connected to PA5
NucleoUserLED.pGPIO = GPIOA;
NucleoUserLED.GPIO_Pin_Cfg.GPIO_PinNumber = GPIO_PIN_5;
NucleoUserLED.GPIO_Pin_Cfg.GPIO_PinMode = GPIO_MODE_OP;
NucleoUserLED.GPIO_Pin_Cfg.GPIO_PinPuPdControl = GPIO_IP_NO_PUPD;
NucleoUserLED.GPIO_Pin_Cfg.GPIO_PinOpType = GPIO_OP_TYPE_PP;
//User blue button in the nucleo connected to PC13
NucleoUserPB.pGPIO = GPIOC;
NucleoUserPB.GPIO_Pin_Cfg.GPIO_PinNumber = GPIO_PIN_13;
NucleoUserPB.GPIO_Pin_Cfg.GPIO_PinMode = GPIO_MODE_IP;
NucleoUserPB.GPIO_Pin_Cfg.GPIO_PinPuPdControl = GPIO_IP_NO_PUPD;
//User led in the bread board connected to PC8
BreadBoardLED.pGPIO = GPIOC;
BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinNumber = GPIO_PIN_8;
BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinMode = GPIO_MODE_OP;
BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinPuPdControl = GPIO_IP_NO_PUPD;
BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinOpType = GPIO_OP_TYPE_PP;
//User DPDT connected in the breadboard connected to PC6
BreadBoardPB.pGPIO = GPIOC;
BreadBoardPB.GPIO_Pin_Cfg.GPIO_PinNumber = GPIO_PIN_6;
BreadBoardPB.GPIO_Pin_Cfg.GPIO_PinMode = GPIO_MODE_IP;
BreadBoardPB.GPIO_Pin_Cfg.GPIO_PinPuPdControl = GPIO_IP_PU;
GPIO_PeriClkCtrl(GPIOA, ENABLE);
GPIO_PeriClkCtrl(GPIOC, ENABLE);
GPIO_Init(&NucleoUserLED);
GPIO_Init(&NucleoUserPB);
GPIO_Init(&BreadBoardLED);
GPIO_Init(&BreadBoardPB);
while(1)
{
/*****************************************************************
* Controlling the IO present in the nucleo board *
*****************************************************************/
inputVal = GPIO_ReadInputPin(NucleoUserPB.pGPIO, NucleoUserPB.GPIO_Pin_Cfg.GPIO_PinNumber);
BBinpVal = GPIO_ReadInputPin(BreadBoardPB.pGPIO, BreadBoardPB.GPIO_Pin_Cfg.GPIO_PinNumber);
if(inputVal == 0)
{
GPIO_ToggleOutputPin(NucleoUserLED.pGPIO, NucleoUserLED.GPIO_Pin_Cfg.GPIO_PinNumber);
}
/*****************************************************************
* Controlling the IO present in the bread board *
*****************************************************************/
if (BBinpVal == 0 )
{
GPIO_WriteOutputPin(BreadBoardLED.pGPIO, BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinNumber, 1);
}
else
{
GPIO_WriteOutputPin(BreadBoardLED.pGPIO, BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinNumber, 0);
}
delay();
}
return 0;
}
It is not a function only the macrodefinition.
Your loop is likely to be optimized out
define it as
void inline __attribute__((always_inline)) delay(uint32_t delay)
{
while(delay--) __asm("");
}
Bear in mind that 50000 can be quite long if you run on low clock settings.
Not sure what the issue is because "it is not working" is not very specific.
However there are "quality" issues:
That is an inappropriate use of a macro - there is no benefit over using a function. The function call overhead argument does not hold - it is a delay, it is supposed to take time!
The empty-loop counter is not declared volatile - the compiler at any optimisation level other then the minimum is likely to remove the loop altogether.
A for-loop for a delay is a crude and generally non-deterministic solution, with a period that will change between compilers, with different compiler options and on different targets or with different clock speeds. STM32 is a Cortex-M device and given that you should use the SYSTICK counter for this. For example, as a minimum something like:
volatile uint32_t tick = 0 ;
void SysTick_Handler(void)
{
tick++ ;
}
void delayms( uint32_t millisec )
{
static bool init = false ;
if( !init )
{
SysTick_Config( SystemCoreClock / 1000 ) ;
init = true ;
}
uint32_t start = tick ;
while( tick - start < millisec ) ;
}
The issue was solved by declaring the iterator as a global variable. Now the LED turns on when the Push button is pressed
Previous implementation
#define delay() for(uint32_t i=0; i<=50000; i++);
Working implementation
uint32_t temp;
void delay(void)
{
for(temp = 0;temp<=50000;temp++)
{
;
}
}
Can any one tell me how declaring the variable as global solves the issue?
Find the working implementation below
#include <stdint.h>
#include "stm32l476xx.h"
#include "stm32l476xx_gpoi_driver.h"
#if !defined(__SOFT_FP__) && defined(__ARM_FP)
#warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif
uint32_t temp;
void delay(void)
{
for(temp = 0;temp<=50000;temp++)
{
;
}
}
int main(void)
{
GPIO_Handle_t NucleoUserLED,NucleoUserPB,BreadBoardLED,BreadBoardPB;
volatile uint8_t inputVal,BBinpVal;
//User green led in the nucleo board connected to PA5
NucleoUserLED.pGPIO = GPIOA;
NucleoUserLED.GPIO_Pin_Cfg.GPIO_PinNumber = GPIO_PIN_5;
NucleoUserLED.GPIO_Pin_Cfg.GPIO_PinMode = GPIO_MODE_OP;
NucleoUserLED.GPIO_Pin_Cfg.GPIO_PinPuPdControl = GPIO_IP_NO_PUPD;
NucleoUserLED.GPIO_Pin_Cfg.GPIO_PinOpType = GPIO_OP_TYPE_PP;
//User blue button in the nucleo connected to PC13
NucleoUserPB.pGPIO = GPIOC;
NucleoUserPB.GPIO_Pin_Cfg.GPIO_PinNumber = GPIO_PIN_13;
NucleoUserPB.GPIO_Pin_Cfg.GPIO_PinMode = GPIO_MODE_IP;
NucleoUserPB.GPIO_Pin_Cfg.GPIO_PinPuPdControl = GPIO_IP_NO_PUPD;
//User led in the bread board connected to PC8
BreadBoardLED.pGPIO = GPIOC;
BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinNumber = GPIO_PIN_8;
BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinMode = GPIO_MODE_OP;
BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinPuPdControl = GPIO_IP_NO_PUPD;
BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinOpType = GPIO_OP_TYPE_PP;
//User DPDT connected in the breadboard connected to PC6
BreadBoardPB.pGPIO = GPIOC;
BreadBoardPB.GPIO_Pin_Cfg.GPIO_PinNumber = GPIO_PIN_6;
BreadBoardPB.GPIO_Pin_Cfg.GPIO_PinMode = GPIO_MODE_IP;
BreadBoardPB.GPIO_Pin_Cfg.GPIO_PinPuPdControl = GPIO_IP_PU;
GPIO_PeriClkCtrl(GPIOA, ENABLE);
GPIO_PeriClkCtrl(GPIOC, ENABLE);
GPIO_Init(&NucleoUserLED);
GPIO_Init(&NucleoUserPB);
GPIO_Init(&BreadBoardLED);
GPIO_Init(&BreadBoardPB);
while(1)
{
/*****************************************************************
* Controlling the IO present in the nucleo board *
*****************************************************************/
inputVal = GPIO_ReadInputPin(NucleoUserPB.pGPIO, NucleoUserPB.GPIO_Pin_Cfg.GPIO_PinNumber);
BBinpVal = GPIO_ReadInputPin(BreadBoardPB.pGPIO, BreadBoardPB.GPIO_Pin_Cfg.GPIO_PinNumber);
if(inputVal == 0)
{
GPIO_ToggleOutputPin(NucleoUserLED.pGPIO, NucleoUserLED.GPIO_Pin_Cfg.GPIO_PinNumber);
}
/*****************************************************************
* Controlling the IO present in the bread board *
*****************************************************************/
temp = 10;
if (BBinpVal == 0 )
{
GPIO_WriteOutputPin(BreadBoardLED.pGPIO, BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinNumber, 1);
}
else
{
GPIO_WriteOutputPin(BreadBoardLED.pGPIO, BreadBoardLED.GPIO_Pin_Cfg.GPIO_PinNumber, 0);
}
delay();
}
return 0;
}
The issue is solved,
There was an bug in the driver layer I have written
Whenever an GPIO is configured as Input, the registers related to Output for that GPIO pin should be set to their reset value or the driver should not implement the API related to the Output
Please give a favor,
I am using MikroC compiler to write a program for 8051 microcontrollers, I am trying to find a way to execute and repeat the main program for 10 seconds, then stop for 2 seconds
Code below just an example, I need to toggle Port two each 200 msec, repeat that for 10 sec, then stop for 2 sec, then repeat this operation.
void main()
{
P2 = 0xAE;
while (1) {
P2 = ~P2;
Delay_ms(200);
}
}
Thank you
You can use a counter to measure the time: For example:
#define MS_PER_TICK 200
#define BLINK_PERIOD_IN_S 10
#define PAUSE_PERIOD_IN_S 2
#define BLINK_PERIOD_IN_TICKS (BLINK_PERIOD_IN_S * 1000 / MS_PER_TICK)
#define PAUSE_PERIOD_IN_TICKS (PAUSE_PERIOD_IN_S * 1000 / MS_PER_TICK)
void main(void) {
unsigned char ticks = 0;
P2 = 0xAE;
for (;;) {
Delay_ms(MS_PER_TICK);
ticks++;
if (ticks <= BLINK_PERIOD_IN_TICKS) {
P2 = ~P2;
}
if (ticks == BLINK_PERIOD_IN_TICKS + PAUSE_PERIOD_IN_TICKS) {
ticks = 0;
}
}
}
I am new to Arduino programming and have spent a couple days getting this far, but cannot seem to figure out why this code is not working.
I am trying to control a stepper motor using a hobby grade remote control RX/TX.
I have an RC receiver sending an analog value from 1000 to 2000 to my Arduino. If that signal is 1000, I would like to make 1000 = -360 degrees on the stepper and 2000 = +360 degrees on the stepper.
I am receiving the correct signals from the receiver and printing them to the serial monitor, but I cant seem to control the stepper motor with this value yet. This motor simply gets stuck in the first while loop and continues to spin in 1 direction.
int ch1 = 0; // RC Reciever Channel Value
int ch1previous = 0; // RC Receiver Channel Previous Value
int PUL=7; //define Pulse pin of stepper driver
int DIR=6; //define Direction pin of stepper driver
int ENA=5; //define Enable Pin of stepper driver
void setup() {
pinMode (PUL, OUTPUT); // Stepper Driver Pulse Pin
pinMode (DIR, OUTPUT); // Stepper Driver Direction Pin
pinMode (ENA, OUTPUT); // Stepper Driver Enable Pin
pinMode(3, INPUT); // RC Reciever Pin Input
Serial.begin(9600);
}
void loop() {
ch1 = pulseIn(3, HIGH, 50000); // Read RC Reciever Channel Value
while ( ch1 > ch1previous) { // If CH1 is greater than CH1Previous run the differance
for ( int i = ch1; i < ch1previous; i++);{ // in steps to maintain the setpoint value in forwared position
digitalWrite(DIR,HIGH);
digitalWrite(ENA,HIGH); // pulsing stepper motor in forward motion
digitalWrite(PUL,HIGH);
delayMicroseconds(50);
digitalWrite(PUL,LOW);
delayMicroseconds(50);
}
}
while ( ch1 < ch1previous) { // if CH1 is less than CH1Previous run the differance
for ( int i = ch1; i<ch1previous; i--);{ // in steps to maintain the setpoint value in reverse motion
digitalWrite(DIR,LOW);
digitalWrite(ENA,HIGH); // pulsing stepper motor in reverse motion
digitalWrite(PUL,HIGH);
delayMicroseconds(50);
digitalWrite(PUL,LOW);
delayMicroseconds(50);
}
}
Serial.print ("Channel 1: "); // print text to the serial monitor
Serial.println(ch1); // print ch1 value to the serial monitor and end line
Serial.print("CH1 Previous: "); // print text to the serial monitor
Serial.println(ch1previous); // print ch1previous value to the serial monitor and end line
ch1previous = ch1; // remember the previous value from ch1
delay(500); // just to clean up the serial monitor
}
Can
ch1 = pulseIn(3, HIGH, 50000)
ever be a negative value? if not, then that could explain this behavior, when you consider this statement:
while ( ch1 > ch1previous) {
and ch1previous is initialized to zero.
Both the while conditions will go on infinitely if they are started even once. As you have put in comments If CH1 is greater than CH1Previous run the difference, these while conditions have to be replaced by if statements. That is, make them as if(ch1 > ch1previous) and else if(ch1 < ch1previous). And for loops' conditions should also be reversed, as per the if condition bounding them.
After these changes, your code will become something like this
void loop() {
ch1 = pulseIn(3, HIGH, 50000);
if ( ch1 > ch1previous) {
for ( int i = ch1; i > ch1previous; i--){
//code
}
}
else if ( ch1 < ch1previous) {
for ( int i = ch1; i<ch1previous; i++){
//code
}
}
...
}
I have connected the LM35 temperature sensor in analog channel of AN1 then transmitting the temperature through serial RS232 in PIC16F887. I have read the temperature value but the value is frequently varying as 31 and 32, also when touch the LM35 temperature is varying very fast as 32, 33 and etc. How to control the constant temperature value. Here is my code, Please any one help me.
#include <htc.h>
void main(void)
{
TRISA1 = 1;
ANS1 = 1;
OSCCON = 0x78; // OSCILLATOR CONTROL REGISTER
TXSTA = 0x26;
RCSTA = 0x90;
SPBRG = 10;
ADCON1 = 0x80;
unsigned int current_temp, initial_temp = temperature();
transmit_char(initial_temp);
flag = 0;
while (1)
{
current_temp = temperature();
if((current_temp == (initial_temp + 1)) || (current_temp == (initial_temp - 1)))
{
flag = 1;
}
if(flag == 1)
{
flag = 0;
transmit_char(current_temp);
initial_temp = current_temp;
}
}
}
int temperature(void)
{
ADCON0 = 0xC5;
GODONE = 1;
while(GODONE);
int temp;
temp = (ADRESH << 8) + ADRESL;
temp = temp/2;
return temp;
}
Do this,
Collect ten adc data,
Remove min and max from that values.
sum the remaining 8 ADC values and divide the value by 8.
this should be continuous process, average for every ten samples
note: sampling and averaging should be ... 1 to 10 , next 2 to 11 and 3 to 12. at every reading you will get the adc value. sudden fluctuations also get filtered here.
Hope this helps.. good luck..