I'm controlling a BLDC motor with an inverter/driver IC doing the switching work.
I need to provide 6 PWM signals for the driver all at the same frequency. The exact frequency doesn't really matter, as long as its between 5kHz to 10kHz and all the PWM pins are the same.
I'm currently using an Arduino Uno, I'm not sure how to program each PWM pin (3, 5, 6, 9, 10, 11) for all the same frequency as the timers(0, 1 and 2) for particular pins have different clock speeds.
Pins 5 and 6: controlled by timer0, base frequency 62500Hz
Pins 9 and 10: controlled by timer1, base frequency 31250Hz
Pins 11 and 3: controlled by timer2, base frequency 31250Hz
timer1 and timer2 will be okay and can be scaled down by the prescaler value 8 (7812.5Hz). Not sure how to get timer0 to the same frequency?
http://playground.arduino.cc/Main/TimerPWMCheatsheet
I'm sure a work around is relatively simple. Is it possible to divide the frequency for timer0 by a number which is not a prescaler value, say 40?
Thanks in advance.
Pat.
You haven't included the chip number for your motor controller, but I'm pretty sure you won't be able to achieve what you want with six different timers. The issue is that the PWM on the different pins all have to be synchronized, not just toggled on and off for the right amount of time.
Instead, you should use a single timer and toggle all the outputs at the correct synchronization. This page has the start of an example in the section "Bit-banging Pulse Width Modulation". You would have to modify it to toggle more pins.
That example is probably still not good enough. Instead, you should be using an interrupt service routine to toggle the pins. That way, the PWM runs more independently and allows the loop function to do more.
Your routine will be attached to an output compare interrupt on a timer, and you will have to keep the values of the various PWM outputs in some volatile variables. The output compare register will be set to wake up for the next toggle. When the routine runs, it will perform the toggle and set the output compare register for the toggle. The details of the timing and synchronization will depend on the datasheet for your controller.
The loop function can read inputs and adjust the volatile variables to change the motor speed.
There are also motor drivers that do all this for you. All you have to do is provide a direction and speed, and the chip creates the 6 PWMs for you.
Related
Im currently trying to get an electric signal from arduino, its 5v and 1amp that i get from a powersupply.
I want to input that signal into an arduino pin, lets say pin 4.
The main powersource from my arduino is via usb, but the 5v signal is from an external device.
I just want to know the number of time that signal became active, like a switch.
As far as i know arduino can take only .04amp from 5v.
Is there anyway i can reduce the current?
Anyway to obtain the value of a resistor to make it less dangerous for my arduino?
Your question is a very common application for Arduino!
You can give your Arduino some additional protection by placing a 10kOhm resistor between the Arduino analog pin you wish to use and the positive voltage output of the power supply.
If you're worried that the voltage could increase above 5V, you can protect your arduino with a simple voltage divider using two resistors. There's a detailed tutorial for this approach here: https://startingelectronics.org/articles/arduino/measuring-voltage-with-arduino/ Here's a simplified circuit diagram with a voltage divider that reduces voltage 11 fold - making voltages up to 55V safe to measure (where the battery could be replaced by your power supply):
For your code, you can use analogread() to read the voltage of the pin. If you wired it correctly, it should return near 0 when the powersupply is at 0, and 1026 or thereabouts if it is at 5v (or whatever the maximum value your voltage divider is designed for). Here is an example to get you started :
https://www.arduino.cc/reference/en/language/functions/analog-io/analogread/
If you need any support with your code to count the number of times the voltage goes high, post that as a separate question along with the code you have so far.
I want to write a stepper motor driver with a STM32L152RE.
I would like to control the position of the stepper motor with a potentiometer.
As I am new, I do not know how to communicate with (DIR, STEP).
Can someone give me a light or show me a way?
I'm using an A4988 - DMOS Microstepping Driver with Translator And Overcurrent Protection
I tried to use STM32 tim, but I could not.
Actually I have wrote whole driver for a4988, it is irq based. But I can't uncover it.
I can describe a path how to start. Anyway you should have some kind of hardware, because A4988 needs extra components for current control (resistors), and some capacitors..
You could try POLOLU HW.
If you have some kind of custom board, there may be some flaws.. So recheck pins.
Especially ROSC pin, SENSE1, SENSE2 pins as those may cause that motor wont work even if other pins are ok.
ROSC pin is for low power mode, so here you should calculate, if you just ignore it, be sure to connect at least to 10k resistor. Don't let it float. SENSE1, SENSE2 pins can be connected to 0.25omh resistors. You should check it.
Also from power pins very decisive VREG pin. It should get from 0 to 2000mV if I remember. Actually it controls current for your motor. So it depends on your stepper motor. Here also may appear nasty flaws. For example you have small stepper motor, and setting too high VREG value, than A4988 will sink too much current and your motor will glitch. Anyway you should read A4988 data sheet very accurately.
DIR PIN is simply for direction, push-pull pin configuration and HIGH/LOW values controls direction, clock wise, anti clock wise.
RESET INPUT PIN A4988 must get HIGH from your MCU.
ENABLE INPUT PIN A4988 must get LOW from your MCU.
SLEEP INPUT PIN A4988 must get HIGH from your MCU, also it is very useful to control it when your stepper job done, else if you leave it always HIGH, stepper motor will eat current and will heat up at idle state.
Also there are 3 MICROSTEPPING PINS, those are for controlling stepping.
As you just starting to play, it will be enough connect those pins to GND, you'll get full stepping regime.If you'll control those pins you can get other regimes like 1/2 stepping, 1/4,1/8,1/16...
And general pin is STEP pin, it should be driven with TIMER as PWM output with constant pulse width and alternating period.
Here is an example of STEP PIN control:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
GPIO_InitTypeDef init;
init.GPIO_Mode = GPIO_Mode_AF;
init.GPIO_OType = GPIO_OType_PP;
init.GPIO_Pin = GPIO_Pin_9;
init.GPIO_PuPd = GPIO_PuPd_UP;
init.GPIO_Speed = GPIO_Speed_Level_2;
GPIO_Init(GPIOA,&init);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_2);
for example I connect STEP output from MCU PA9 to A4988 STEP input. Which can be driven from timer as PWM. Check your concrete MCU datasheet.
Firstly output pin should be configured as AF, with push-pull and resistor is UP.
Also setup line for alternating pin.
Now configuring timer:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TIM_TimeBaseInitTypeDef timerInitStructure;
timerInitStructure.TIM_Prescaler = 48;
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitStructure.TIM_Period = 0;
timerInitStructure.TIM_ClockDivision = 0;
timerInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &timerInitStructure);
TIM_OCInitTypeDef osc;
osc.TIM_OCMode = TIM_OCMode_PWM1;
osc.TIM_OutputState = TIM_OutputState_Enable;
osc.TIM_OutputNState = TIM_OutputNState_Disable;
osc.TIM_Pulse = 1000;
osc.TIM_OCPolarity = TIM_OCNPolarity_High;
osc.TIM_OCNPolarity = TIM_OCNPolarity_Low;
osc.TIM_OCIdleState =TIM_OCIdleState_Reset;
osc.TIM_OCNIdleState =TIM_OCNIdleState_Set;
TIM_OC2Init(TIM1, &osc);
TIM_Cmd(TIM1, ENABLE);
Here I configure 1us timer, as my MCU frequency is 48MHz.
Also you have configure that timer would drive PWM output.
TIM1->CCR = 10; with this register I can control pulse width, in this example it is 10us.
TIM1->ARR = 30; with ARR register I can control period, so it means STEP pulse frequency which is equal to stepper motor speed. In this case 30us.
If you are using HAL and CUBEMX you can get those configurations pretty fast.
I'm working through a set of beginner exercises with the Arduino Uno microcontroller. (A generic one, though, as this is what I've been supplied with.)
The program I'm running, which alternates between sending 1's and 0's to serial output depending on the state of a momentary switch, has set pin 2 to be the input for the switch. But. Whilst wiring up, I accidentally plugged the jumper cable in to pin 3 initially, and found it still mostly sent the 1's when the button was pushed. Some 0's, yet mostly 1's.
Initially I thought maybe it was just the board was a bit dodgy, but thought I'd experiment a bit. Plugging into pin 3 instead of pin 2 still fairly consistently sent 1's when the button was pushed, though the 1's flowed a little bit less consistently than when it was in pin 2. In pin 2 it was completely consistent by comparison. So I tried pin 4, but with that one there's no response at all.
Am I right in presuming the program's readings seems to get a little bit less responsive the further away I move the cable from the pin that I've programmed to act as input? Can anyone help me understand why this happens?
It's probably quite obvious that I'm new to electronics. :)
The program I've got uploaded to the board is as follows:
// digital pin 2 has a pushbutton attached to it. Give it a name:
int pushButton = 2;
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
// make the pushbutton's pin an input:
pinMode(pushButton, INPUT);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input pin:
int buttonState = digitalRead(pushButton);
// print out the state of the button:
Serial.println(buttonState);
delay(1); // delay in between reads for stability
}
Floating pins are prone to noise. If you are not actually connecting anything to pin 2, you will be reading noise. Any wire connected to pin 2 (even connections on the board) will act like an antenna and pick up noise. You should always use the pin number that you are physically connecting in situations like these.
Leaving input pins open makes the microcontroller read a floating value which swings between 0 to 1. Also when wiring a switch to any pin, make sure to hook some pull-down resistor to make the input 0.
These are common for many electronics and proper notice to be taken while designing circuits of your own.
You need to look into datasheet where described functions of the pins.
The pins of MCU can be assigned various functions through special registers.
Two most common functions of the pins are input and output. MCUs provide internal pull-up and pull-down resistors which when used properly significantly simplifies electronic schemas.
If the input activated as input without any pull-??? then it's state is not defined and can be used as initiator of random number generator. Due this reason it is better to define what is default state of the input pin by connecting pull-??? resistors.
In Arduino IDE you are not limited to functions provided -- you still can use register manipulation directly, you just need to learn internals of the MCU.
If you do it properly then 2kbit program very often can be made as small as a few hundred bytes and it will work hundred times faster.
Operating registers in C is not much different from assembly, in C++ you get right away significant overhead -- although some benefits of registers still can be significant.
Libraries hide from programmers internals of MCU what is nice as it simplifies the programming and does not require to understand how MCU works, what registers are changed in what sequence.
But when you know hardware in and out -- you can squeeze from small MCU what is not possible with use of libraries (code will just not fit into the chip). MCUs are not that complicated (Atmel) to learn about it's internals -- benefits are significant.
Knowledge is a power which many avoid.
I am currently using analog pin 3 on my Arduino Uno to send out voltage from 0 to 5V.
I am using that voltage to control the motor and currently I am using the function:
analogWrite(pin, PWM_PULSE);
I am using 255 pwm for 5V and 127 for 2.5V.
The problem is that PWM is sending full cycle at 255pwm(5V), but on 127V the cycle is at 50% which causes my motor to twitch a little bit.
How can I solve this? I am searching for a way to send full PWM cycle even at lower volts. Is it possible?
First I believe you mean D3 not A3, since PWM does not exist on A3.
Assuming you are driving a DC motor, and not something like a servo or stepper
You have two problems.
1st. you may need a smoothing capacitor. Where your formula would be F=L*C Noting that analogWrite uses a F=490Hz. The concept is simple, in short the cap average out the high and lows of the PWM, based on the duty cycle. And the capacitance needed is based on the frequency and impedance. This will provide the analog voltage.
2nd. And bigger problem is the output of the Arduino can not supply sufficient current to drive the motor correctly. It will max out at about 20ma, and the motor likely needs more. So at low speeds the pulses which were week, stall out during their low periods.
You should have your PWM output drive a transistor, which in turn will ON-OFF the motor directly from the power supply. Now your motor may have enough inertia as not to need the cap.
see adafruit-arduino-lesson-13-dc-motors/breadboard-layout
and here for a discussion about the smoothing cap
I know this sounds a bit funny :). But I am trying to eliminate possibilities:
On the Arduino Uno I have attached an interrupt triggered on HIGH to a routine which only increments a volatile defined long counter. This counter is displayed on an LCD screen.
If I connect a pulse generator with a frequency of 1 Hz at TTL levels, I would expect the counter to increase with about 1 per second. However this is not the case.
As the frequency is 1 Hz (duty cycle 50%) could it be possible that once the counter is incremented the IRS is exited (and clears the interrupt flag) BUT: the INT0 level is still HIGH so the ISR would be called again? At 1 Hz 50% duty, the HIGH would stay for 500 ms and at 16 mHz...
The processor at the heart of any Arduino has two different kinds of interrupts: “external”, and “pin change”. There are only two external interrupt pins on the ATmega168/328 (ie, in the Arduino Uno/Nano/Duemilanove), INT0 and INT1, and they are mapped to Arduino pins 2 and 3. These interrupts can be set to trigger on RISING or FALLING signal edges, or on low level. The triggers are interpreted by hardware, and the interrupt is very fast. The Arduino Mega has a few more external interrupt pins available.
So as commented: It triggers on an edge!
See more details on the Arduino Playground web page.
Two electrical reasons can explain why interrupt does not function as you need.
1- The pulse generator output and MCU input can have an impedance mismatch, which can cause ringing on the waveform edges. For example, if your function generator has a 50 ohm output capable of generating high frequencies you might see a problem driving a high impedance input like the Arduino at low frequency.
The name "pulse generator" makes me think this is a 50 ohm out device intended to make very short pulses with sharp edges. In such a case, you add a terminating resistor at the destination (load) to match the impedance of the source (pulse generator). For a 50 ohm output, 47 ohm would be close enough. If the output is 100 kohm, then place a matching resistor at the Arduino.
2- Just the opposite, the generator waveform edges may be so slow that the voltage passes through TTL 0 to 1 transition multiple times. If you have noise on your signal input, a slow edge could be causing multiple triggers. For example, if you are picking up some 60 Hz ripple from a power supply and grounding issues, your square wave edges won't be as square as you think.
In such cases hysteresis is a solution. There are many ways to de-glitch (debounce) in code. There is no answer that is right for all problems. A simple example would be that the ISR you require that the input reads high twice in a row for the edge to be accepted.