I use an STM32F microcontroller on the Keil. I have a problem on while or for loops. The shared code is my faulty section. My for or while loop does not work. I stayed "step = 2" and "counter = 0". I tryed released and debug mode. Debug mode I saw this results watch screen;
step = 1 (WaitData = 1) after systemtick increase after that systemtick = 5000 after that step = 2 (systemtick = 0 waitdata = 0) but code stack on the for loop.
#include "stm32f4xx_hal.h"
#include <stdio.h>
#include <stdlib.h>
int step = 0;
int waitdata = 0;
int systemtick1 = 0;
int counter = 0;
void HAL_SYSTICK_Callback(void)
{
if (WaitData == 1)
{
systemtick1++;
if (systemtick1 == 5000)
{
step = 2;
systemtick1 = 0;
WaitData = 0;
}
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
HAL_Delay(2000);
step = 1;
WaitData = 1;
for (; WaitData==1 ; ) // Or while (WaitData == 1);
{
asc++;
}
step = 3;
while (1)
{
}
}
The variables you are changing in interrupt needs to be set as volatile, because you don't know how the compiler will optimize it.
The access to the variables is mostly done in sequential, predictable way. But interrupt isn't predictable; therefore you need to use volatile to be able to change the variable outside of the normal "program" flow.
Related
I am using MPLAB to perform an operation on PIC kit 14f458.
Now I want to create a code to pass the different amount of voltage supply LED through the Microcontroller using a button. When button pressed the first time I should get waveform with 10% DC, for second and third time, 50% and 95% respectively.
I have worked on this But still getting Values OF RE2 PORT as 0 rather than 1. And I also don't know how to stop timer while I release the button.
My code is as follow:
#include<stdio.h> //Standard I/O Library
#include<p18cxxx.h> //for TRISA,E and PORTA,E declaration
#pragma config WDT = OFF //watchdog counter
#pragma config OSC = HS, OSCS = OFF
#pragma config PWRT = OFF, BOR = ON, BORV = 45
#pragma config DEBUG = OFF, LVP = OFF, STVR = OFF
void timer_10()
{
CCP1CON = 0;
PR2 = 249;
CCPR1L = 24;
TRISCbits.TRISC2 = 0;
T2CON = 0x00;
CCP1CON = 0x3c;
TMR2 = 0;
T2CONbits.TMR2ON = 1;
while(1)
{
PIR1bits.TMR2IF = 0;
while(PIR1bits.TMR2IF == 0);
}
}
void timer_50()
{
CCP1CON = 0;
PR2 = 249;
CCPR1L = 124;
TRISCbits.TRISC2 = 0;
T2CON = 0x00;
CCP1CON = 0x2c;
TMR2 = 0;
T2CONbits.TMR2ON = 1;
while(1)
{
PIR1bits.TMR2IF = 0;
while(PIR1bits.TMR2IF == 0);
}
}
void timer_95()
{
CCP1CON = 0;
PR2 = 249;
CCPR1L = 236;
TRISCbits.TRISC2 = 0;
T2CON = 0x00;
CCP1CON = 0x2c;
TMR2 = 0;
T2CONbits.TMR2ON = 1;
while(1)
{
PIR1bits.TMR2IF = 0;
while(PIR1bits.TMR2IF == 0);
}
}
void main()
{
int i = 1;
ADCON1 = 0x06; //Sets RA0 to digital mode
CMCON = 0x07;
TRISEbits.TRISE2 = 1; //set E2 PORTE pins as input
PORTEbits.RE2 = 1; //Here I am not able to SET Value 1
while(1)
{
while(PORTEbits.RE2 == 0)
{
switch(i)
{
case 1:
timer_10();
break;
case 2:
timer_50();
break;
case 3:
timer_95();
break;
}
if(i<4)
{
i++;
if(i>=4)
{
i=1;
}
}
}
}
}
And My compiler Get Stuck in function timer_10(). Please help me.
This is a bit too long for a comment, and I think you're probably able to discover the answer yourself - however, I'll give you some pointers.
In main()
TRISEbits.TRISE2 = 1; //set E2 PORTE pins as input
PORTEbits.RE2 = 1; //Here I am not able to SET Value 1
What behaviour do you expect when you write to port E2 after configuring E2 as an input? It is described in the PIC18F458 data sheet, specifically section 9.5
In timer_10()
void timer_10()
{
CCP1CON = 0;
PR2 = 249;
CCPR1L = 24;
TRISCbits.TRISC2 = 0;
T2CON = 0x00;
CCP1CON = 0x3c;
TMR2 = 0;
T2CONbits.TMR2ON = 1;
while(1)
{
PIR1bits.TMR2IF = 0;
while(PIR1bits.TMR2IF == 0);
}
}
You said your compiler got stuck, but I assume you mean debugger, as you were able to run main() to observe PORTEbits.RE2 = 1; not doing what you expected. If you single-step this in function a debugger, where does it get stuck? can you see why?
Ok, let's simplify this a bit. If you want the duty cycle to change on the negative edge of a push button, and you don't want to use interrupts, then you need to restructure what you have. Firstly, there are several issues with the timer_x routines: 1) you don't need the while loop in there, that is why you are getting stuck. 2) If you remove that loop, you will constantly call a timer routine which will reset the register values and you will not get what you expect. Also, since you are not using interrupts, who cares if the overflow flag is set or not, just leave it set.
To fix this, first, remove all the timer_x routines. Next, you need a timer routine to read the switch input. Remember that all switches have switch bounce so reading one value isn't reliable. You either need to read the switch slowly, at a rate greater than the switch bounce (~50ms) and only run your routines if you have two readings in a row that are the same, or you can read it faster, but you will need more readings that are the same to know you have a stable value.
From there, you can only increment "i" on the first negative edge, not all the time the switch is held down (unless you want it that way). your main routine should look something like (forgive the shortcut for the timer registers):
Main()
if (tmr2.overflow) // 50ms switch read timer
{
switchCurrent = PORTE2;
}
if ( (switchCurrent == swtichLast) // Two readings of the same value
&& (!switchCurrent) // and switch is pressed
&& (!switchUpdated) ) // and haven't updated the pwm yet
{
switchUpdated = TRUE; // Only allow one update per switch
i++;
if (i > 4)
{
i = 0;
}
switch (i)
{
case 0:
CCPR1L = 24;
break;
case 1:
CCPR1L = 124;
break;
... and so on. Note, the only difference in each case is CCPR1L, so just rewrite that register instead of resetting everything.
}
switchLast = swtichCurrent;
if (swtichCurrent)
switchUpdated = 0
This should give you a starting point, hope it helps
I have a program that moves a stepper motor to the right, left and have a stop button that stops the motor. In one part of my program, a motor gradually lowers a speed and stops after a certain period of time iv.
The problem is that in this part of a program (when a motor gradually lowers a speed and then stops) I can’t stop the motor upon pressing a stop button. I understand that I need to break a while loop somehow, but using a break statement doesn't wort for me.
Do you have some ideas?
Here is my function:
/* --- STEPPER MOTOR ---*/
const int motor_step = 3;
const int motor_dir = 4;
int stepSpeed = 0;
int stepMaxSpeed = 1000;
int fadeAmount = 100;
int fadeDelay = 10;
/* ---- STOP BUTTON ---- */
int buttonStop = 5;
int stateStop=0;
void setup() {
.
.
.
stateStop = digitalRead(buttonStop);
}
void loop () {
.
.
.
myfunc();
}
void myfunc() {
if(stateStop == HIGH) {noTone(motor_step); stepSpeed = 0;}
elapsedMillis te;
unsigned int iv = 1500;
while (te < iv) {
if(stepSpeed == stepMaxSpeed) {
stepSpeed = stepSpeed+0;
tone(motor_step,stepSpeed);
digitalWrite(motor_dir,HIGH);
}
else {
stepSpeed = stepSpeed + fadeAmount;
tone(motor_step,stepSpeed);
digitalWrite(motor_dir,HIGH);
delay(fadeDelay);
}
if(stateStop == HIGH) { stepSpeed = 0; break;}
}
if(stepSpeed == stepMaxSpeed) {
while(stepSpeed>0){
stepSpeed = stepSpeed-fadeAmount;
tone(motor_step,stepSpeed);
digitalWrite(motor_dir,HIGH);
delay(fadeDelay);
if(stateStop == HIGH) { stepSpeed = 0; break;}
}
}
stepSpeed = 0;
noTone(motor_step);
digitalWrite(enable,LOW); // enable changed from HIGH
}
Your break condition does never trigger as stateStop is never being updated inside your while loop. How is your program supposed to know? It's busy running the loop and does not care about anything outside it's scope.
Check the button state inside the while loops or use interrupts
I'm trying to get myself familiar with Interrupts when it comes to the 18F4550 PIC. At this point I've written a software that would light up an LED whenever the INT0 raises a flag.
My code states that every 500 ms, INT0 will raise a flag and "is supposed to" jump into an ISR and fire up a LED all while "transferring dummy data between Port C and Port D"
I've tried debugging, but once the debugger gets to the code that sets the INT0 flag to 1, the debugger says "No source code lines were found at current PC".
Here's the code below. Any kind of help is greatly appreciated. Thanks a lot!
Please note that I am using MPLAB X and a PicKit3
#include <xc.h>
#include <p18f4450.h>
#include <stdlib.h>
#define mybit LATBbits.LATB1 //LED
#define _XTAL_FREQ 10000000 //Using a crystal oscillator
void chk_isr(void);
void INT0_ISR(void);
void delay(unsigned int);
#pragma interrupt chk_isr //used for high-priority interrupt only
void chk_isr (void)
{
if(INTCONbits.INT0IF == 1) //INT0 causes interrupt?
INT0_ISR(); //Yes, Execute INT0ISR
}
#pragma code My_HiPrio_Int=0x08//high priority interrupt
void My_HiPrio_Int (void)
{
asm("GOTO chk_isr");
}
void main(void)
{
TRISBbits.TRISB1 = 0; //RB1 = output
mybit = 0; //Initially LED is OFF
TRISC = 0xFF; //PORTC = input
TRISD = 0; //PORTD = output
INTCONbits.INT0IF = 0; //clear INT0
INTCONbits.INT0IE = 1; //enable INT0 interrupt
INTCONbits.GIE = 1; //enable all interrupts globally
while(1)
{
PORTD = PORTC;
delay(500); //After 500 ms
INTCONbits.INT0IF = 1; //Flag
}
}
void INT0_ISR(void)
{
mybit=~mybit; //Toggle LED
INTCONbits.INT0IF = 0; //clear INT0 Flag
}
void delay(unsigned int delayInput) {
unsigned int mul = delayInput/50;
unsigned int count = 0;
for (count = 0; count <= mul; count ++)
__delay_ms(50);
}
On my Arduino Mega 2560, I'm trying to run a motor that turns a 20-vial container (accepting int input 1-20) while regulating temperature via PID of a separate cooler. I am generally new to this field of technology so bear with me. I also have an interrupt set up for an encoder to keep track of vial position.
The void serialEvent() and void loop() are the most important portions to look at, but I decided to put the rest of the code in there just in case you needed to see it.
#include <PID_v1.h>
#include <SPI.h>
#include <TMC26XStepper.h>
#define COOL_INPUT 0
#define PIN_OUTPUT 9
TMC26XStepper tmc26XStepper = TMC26XStepper(200,5,7,6,500);
int step = 6;
int value;
int i;
char junk = ' ';
volatile long enc_count = 0;
const byte interruptPinA = 2;
const byte interruptPinB = 3;
//Define Variables we'll be connecting to
int outMax = 255;
int outMin = -145;
double Setpoint, Input, Output;
double heatInput, heatOutput, originalInput;
//Specify the links and initial tuning parameters
// AGGRESSIVE VALUES (to get to 4 deg C)
double aggKp=8.0, aggKi=3.0, aggKd=0.15;
// CONSERVATIVE VALUES (to hover around 4 deg C)
double consKp=2.5, consKi = 0.0, consKd = 1.0;
PID myPID(&Input, &Output, &Setpoint, aggKp, aggKi, aggKd, REVERSE);
void setup()
{
pinMode(step, OUTPUT);
pinMode(interruptPinA, INPUT_PULLUP);
pinMode(interruptPinB, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPinA), encoder_isr, CHANGE);
attachInterrupt(digitalPinToInterrupt(interruptPinB), encoder_isr, CHANGE);
//initialize the variables we're linked to
Input = (5.0*analogRead(COOL_INPUT)*100.0) / 1024;
Setpoint = 10.75;
myPID.SetOutputLimits(outMin, outMax);
//turn the PID on
myPID.SetMode(AUTOMATIC);
Serial.begin(115200);
tmc26XStepper.setSpreadCycleChopper(2,24,8,6,0);
tmc26XStepper.setMicrosteps(32);
tmc26XStepper.setStallGuardThreshold(4,0);
Serial.println("...started...");
tmc26XStepper.start();
Serial.flush();
Serial.println("Enter vial numbers 1-20");
}
void loop() {
Input = (5.0*analogRead(COOL_INPUT)*100.0) / 1024;
// A BUNCH OF CODE FOR TEMP REGULATION
Serial.println(Input);
delay(150);
}
void serialEvent() {
while (Serial.available() == 0) {}
i = Serial.parseInt();
Serial.print("position: ");
Serial.print(i);
Serial.print(" ");
while (Serial.available() > 0) {
junk = Serial.read();
}
if (i == 1) {
value = 0;
} else {
int num = i - 1;
value = num * 72;
}
while (enc_count != value) {
digitalWrite(6, HIGH);
delayMicroseconds(100);
digitalWrite(6, LOW);
delayMicroseconds(100);
if (enc_count == 1440) {
enc_count = 0;
}
}
Serial.println(enc_count);
}
// INFO FOR ENCODER
void encoder_isr() {
static int8_t lookup_table[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
static uint8_t enc_val = 0;
enc_val = enc_val << 2;
enc_val = enc_val | ((PIND & 0b1100) >> 2);
enc_count = enc_count + lookup_table[enc_val & 0b1111];
}
So, originally I had the two processes tested separately (vial position + encoder, then temperature regulation) and everything did exactly as it was supposed to. Now, I fused the code together and stored the vial position entry in the serialEvent() method to keep the temperature reading continuous and the vial position entry available for whenever I decided to provide input. However, when I put in a value, the program stops all together. I am able to see the number I entered (position: 5), but the Serial.println(enc_count) never gets printed. On top of the that, the temperature readings stop displaying readings.
Any thoughts? Need more information?
I am trying to write a simple program to take input from user by hterm, when User enters "motor" & "25" the motor will rotate in 25 clockwise and 25 anticlockwise direction
//Define clock-speed and include necessary headers
#define F_CPU 1000000
#include <avr/io.h>
#include <util/delay.h>
#include <inttypes.h>
#include <avr/io.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdint.h>
#include <util/delay.h>
#include <ctype.h>
#define F_CPU 16000000UL
#define BAUD 9600UL
char cmd[40];
void uart_init(void) // initializing UART
{
UBRRH = 0;
UBRRL = ((F_CPU+BAUD*8)/(BAUD*16)-1);
UCSRC |= 0x86; // 8N1 Data
UCSRB = 0x18; // Receiving and Transmitting
}
int uart_putch(char ch, FILE *stream) // Function for sending Data to PC
{
if (ch == '\n')
uart_putch('\r', stream);
while (!(UCSRA & (1<<UDRE)));
UDR=ch;
return 0;
}
int uart_getch(FILE *stream) // Function for receiving Data from PC
{
unsigned char ch; while (!(UCSRA & (1<<RXC)));
ch=UDR;
uart_putch(ch,stream); // Echo the output back to the terminal
return (tolower(ch));
}
FILE uart_str = FDEV_SETUP_STREAM(uart_putch, uart_getch, _FDEV_SETUP_RW); // Important, not deleting
void loeschen() // Delete the String
{
int strnglen = 0;
while (strnglen < 41 && cmd[strnglen] != 0)
{
cmd[strnglen]= 0;
strnglen++;
}
}
// Define the stepping angle
// Note: Divide by 2 if you are doing half-stepping. for filter test 1.8 defult
#define MIN_STEP 1.8
/* Define an array containing values to be sent at the required Port - for Full-stepping
<first four bits> - <last four bits> = <decimal equivalent>
00000001 = 1 ; 01000000 = 4
00000100 = 4 ; 00010000 = 16
00000010 = 2 ; 00001000 = 8
00001000 = 8 ; 00100000 = 32
*/
unsigned short control_array_full[4] = {4,16,8,32};
/* Define an array containing values to be sent at the required Port - for Half-stepping
<first four bits> - <last four bits> = <decimal equivalent>
0000-1001 = 8 + 1 = 9 ; 0010-0100 = 32 + 4 =36
0000-0001 = 1 ; 0000-0100 = 4
0000-0101 = 4 + 1 = 5 ; 00010100 = 16 + 4 = 20
00000100 = 4 ; 00010000 = 16
00000110 = 4 + 2 = 6 ; 00011000 = 16+8=24
0000-0010 = ; 00-001000 = 8
0000-1010 = 8 + 2 = 10 ; 00-101000 = 40
0000-1000 = 8 ; 00-100000 = 32
*/
unsigned short control_array_half[8] = {36,4,20,16,24,8,40,32};
// Adjust this delay to control effective RPM
// Do not make it very small as rotor will not be able to move so fast
// Currently set at 100ms
void delay()
{
_delay_ms(100);
}
void move_clockwise(unsigned short revolutions){
int i=0;
for (i=0; i < (revolutions* 360 /MIN_STEP) ; i++)
{
//Note: Take modulo (%) with 8 when half-stepping and change array too
PORTD = control_array_half[i % 4];
delay();
}
}
void move_anticlockwise(unsigned short revolutions){
int i;
for (i = (revolutions* 360 /MIN_STEP); i > 0 ; i--){
//Note: Take modulo (%) with 8 when half-stepping and change array too
PORTD = control_array_half[i % 4];
delay();
}
}
int main()
{
// Enter infinte loop
// Make changes here to suit your requirements
uart_init(); // initializing UART
stdout = stdin = &uart_str; // Necessary to compare whole Strings
while(1){
scanf("%s",&cmd); // Read String from Data Register
printf ("Please enter number of motor rotation for clockwise and anticlockwise");
items_read = scanf ("%d", &numbers[i]); // Read integer for motor revolution
if(strcmp(cmd, "motor") == 0)
{
DDRD = 0b00111110; //Set PORTD 4 bits for output
//Enter number of revolutions required in brackets
move_clockwise(items_read);
move_anticlockwise(items_read);
}
DDRD = 0b00000000;
}
loeschen();
}
Now, The problem is that when I will delete these lines from main()
items_read = scanf ("%d", &numbers[i]);
scanf ("%d",&i);
& make items_read in move_clockwise(items_read); as:
move_clockwise(25);
move_anticlockwise(25);
Then when user enters "motor" then motor is running move_clockwise(25); but move_anticlockwise(25); is not running, what I would like is to take both "motor", number for clockwise and number for anticlockwise....
I would really appreciate if anyone can help me with this!
Thanks in advance!
First, in my opinion you're only clearing "cmd" in loeschen(), but you never assining any value.
Second "cmd" is NOT any type of UART dataregister.
DDRD is DataDirectionRegister D, that means you can set some pin to input or output mode.
Use PORTD to set a pin high or low, in example PORTD |= 1<<PD0; to set Port D Pin 0 to high.
I guess you prefer german documentation, because you named one function "loeschen()" ;-), so why don't you visit mikrocontroller.net AVR GCC Tutorial (UART)?
If you like more technic detailed youtube-stuff, et voila: Introduction to UART
RXT (ATMEGA16) - for example:
//////////////////////////////////////////////////////////////////////////
// Definitions
//////////////////////////////////////////////////////////////////////////
#define BAUD 9600UL
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
#error Baud to high
#endif
#define UART_MAX_STRING_LENGHT 20 // Max lenght
//////////////////////////////////////////////////////////////////////////
// UART-Receive-Variables
//////////////////////////////////////////////////////////////////////////
volatile uint8_t uart_str_complete = 0; // FLAG - String received
volatile uint8_t uart_str_count = 0; // Current position
volatile char uart_string[UART_MAX_STRING_LENGHT + 1] = ""; // received string
//////////////////////////////////////////////////////////////////////////
// ISR-UART
//////////////////////////////////////////////////////////////////////////
ISR(USART_RXC_vect)
{
unsigned char nextChar;
nextChar = UDR; // read data from buffer
if(uart_str_complete == 0) // UART-String is currently usen
{
if(nextChar != '\n' && nextChar != '\r' && uart_str_count < UART_MAX_STRING_LENGHT)
{
uart_string[uart_str_count] = nextChar;
uart_str_count++;
}
else
{
uart_string[uart_str_count] = '\0';
uart_str_count = 0;
uart_str_complete = 1;
}
}
}
//////////////////////////////////////////////////////////////////////////
// Init UART
//////////////////////////////////////////////////////////////////////////
void Init_UART_Async()
{
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;
UCSRB |= (1<<TXEN); // UART TX high
UCSRB |= (1<<RXEN); // UART RX high
UCSRB |= (1<<RXCIE); // UART RX Interrupt enable
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // Asynchron 8N1
sei(); // Enable interrups
}
//////////////////////////////////////////////////////////////////////////
// Main
//////////////////////////////////////////////////////////////////////////
int main(void)
{
Init_UART_Async();
while(1)
{
HandleCommunication(); // <-- Handle your communication ;-)
// and to some other cool stuff here
}
}
//////////////////////////////////////////////////////////////////////////
// Handle Communication
//////////////////////////////////////////////////////////////////////////
void HandleCommunication()
{
if(uart_str_complete == 1)
{
strcpy(received_string, uart_string); // copy received string
strcpy(uart_string, ""); // empty uart-string
uart_str_complete = 0; // set flag to 0
// handle your communication
}
}
After understanding how UART is working, you should check your codeparts
like "scanf("%s",&cmd);" in an console-application - that's easier to find some errors.
I hope this helps you a little, but I guess the best solution is when you're knowing what you're doing.
-Crazy