Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed
main.cpp
- Committer:
- duncan_120
- Date:
- 2021-11-16
- Revision:
- 1:1e5da28e18ba
- Parent:
- 0:56821d19bd29
File content as of revision 1:1e5da28e18ba:
////////////////////////////////////////////////////////////////////////////////
// System Identification for DC Motors //
// A is for left B is for right //
// //
////////////////////////////////////////////////////////////////////////////////
/*
- Modify the Hardware setting about PWM. Setting register that related to PWM output
directly, instead of using Mbed's API about PWM.
- It may provide your motor better performance.
*/
#include "mbed.h"
#include <math.h>
#define pi 3.14159f //(is defined for) changing unit from rpm to rad/s
/////////////////////////////////////////////////////// you need to modify first
#define VELOCITY_CMD 12.0f // unit:voltage
///////////////////////////////////////////////////////
#define INPUT_VOLTAGE 12.0f
#define PWM_FREQUENCY 1.0f // (unit : kHz) you may need to change. Recommand don't exceed 100.0 (100 kHz)
#define PWM_STOP 0.5f //the range of pwm dutycycle value is from 0~1 and the value that can let motor stop is 0.5.
#define HALL_RESOLUTION 60.0f //Encoder number per one circle HALL SENSOR
#define FRICTION_VOLTAGE 0.0f
#define CONTROLLER 0 // 0 for transfer function , 1 for control
Serial pc(USBTX,USBRX);
InterruptIn mybutton(USER_BUTTON);
Ticker main_function; //interrupt function
PwmOut pwm1A(D7);
PwmOut pwm1B(D8);
PwmOut pwm2A(D11);
PwmOut pwm2B(A3);
DigitalOut led1(LED1);
float dt = 0.01; // unit:second
float command = 0;
float velocityA = 0;
float velocityB = 0;
bool button_state = false;
float dutycycle = PWM_STOP;
float you_need_to_do = 0.5;
short preEncoderPositionA = 0;
int flag = 0;
void step_command();
void position_control();
void ReadVelocity();
void motor_drive(float voltA, float voltB);
void InitMotor(float pwm_frequency);
void InitEncoder(void);
uint16_t CCR_value(float duty);
int main() {
pc.baud(115200); //default baud rate
InitEncoder(); //don't change it
InitMotor(PWM_FREQUENCY); // Set pwm period. Don't change the contents in this function unless you know what you do
mybutton.fall(&step_command); // if you push blue botton, step_command will work
main_function.attach_us(&position_control, dt*1000000); //dt*1000000 changing unit to second.
while(1){}
}
void InitMotor(float pwm_frequency) {
uint16_t reload = 90000000 / int(pwm_frequency * 1000) - 1;
uint16_t stop = 90000000 / int(pwm_frequency * 1000) / 2 - 1;
TIM1->CR1 &= (~0x0001); // CEN(Counter ENable) = '0' < TIM control register 1 ;Disable counter at initial
TIM1->PSC = 0x0001; // Prescaler = ('1' + 1) < TIM prescaler ;Prescaler timer for Timer 1
TIM1->ARR = reload; // reload at 180MHz/PSC/PWM freq -1 < TIM auto-reload register ;Set auto-reload, the pwm freq is (timer_clk /PSC /ARR)
TIM1->CCMR1 |= 0x0808; // set PWM mode, preload < TIM capture/compare mode register 1 ;Not necessary
TIM1->CCER |= 0x0055; // CC2NE CC2E CC1NE CC1E < TIM capture/compare enable register ;Enable complementary PWM for channel 1, channel 2
TIM1->BDTR |= 0x0C00; // OSSI OSSR < TIM break and dead-time register ;Set off-state selection
TIM1->EGR = 0x0001; // UG < TIM event generation register ;Update generation
TIM1->CR1 |= 0x0001; // CEN(Counter ENable) = '1' < TIM control register 1 ;Enable counter
/*
// used for debug
pc.printf("CR1 : %d\r",uint16_t(TIM1->CR1));
pc.printf("PSC : %d\r",uint16_t(TIM1->PSC));
pc.printf("ARR : %d\r",uint16_t(TIM1->ARR));
pc.printf("CCMR1 : %x\r",TIM1->CCMR1);
pc.printf("CCER : %x\r",TIM1->CCER);
pc.printf("BDTR : %x\r",TIM1->BDTR);
pc.printf("EGR : %x\r",TIM1->EGR);
pc.printf("stop : %d\r",stop);
*/
TIM1->CCR1 = stop;
TIM1->CCR2 = stop;
}
void step_command() {
led1 = !led1;
button_state = !button_state;
/////////////////////////////////////////////////////// maybe you need to do something here
///////////////////////////////////////////////////////
}
void position_control() {
#if CONTROLLER == 0
if(button_state == true){
ReadVelocity();
command = VELOCITY_CMD;
pc.printf("%.3f, %.3f\r\n",command, velocityA);
motor_drive(command,0);
}
else{
ReadVelocity();
dutycycle = PWM_STOP;
TIM1->CCR1 = CCR_value(dutycycle);
TIM1->CCR2 = CCR_value(dutycycle);
pc.printf("1.8,%.3f\r\n",velocityA);
}
#endif
#if CONTROLLER == 1
// for lab3
#endif
}
void ReadVelocity() {
short EncoderPositionA;
short EncoderPositionB;
short pEncoderPositionA;
EncoderPositionA = TIM2->CNT ;
EncoderPositionB = TIM3->CNT ;
// if you want count to zero you can do it
// TIM2->CNT = 0;
// TIM3->CNT = 0;
/////////////////////////////////////////////////////// maybe you need to do something here
pEncoderPositionA = EncoderPositionA - preEncoderPositionA;
//pc.printf("EPA = %d\r, preEPA = %d\r, pEA = %d\r, V = ", EncoderPositionA, preEncoderPositionA, pEncoderPositionA);
if(pEncoderPositionA < 0){
pEncoderPositionA = -pEncoderPositionA;
}
//you_need_to_do = dt*64;
preEncoderPositionA = EncoderPositionA;
///////////////////////////////////////////////////////
velocityA = pEncoderPositionA/(dt*64/60);
// please refer to PPT. (then you will find out you may need to add some variables)
velocityB = EncoderPositionB/you_need_to_do;
//pc.printf("%.4f\r\n",velocityA);
}
void motor_drive(float voltA, float voltB){
/////////////////////////////////////////////////////// maybe you need to put some constraints here
you_need_to_do = (voltA + INPUT_VOLTAGE)/(2*INPUT_VOLTAGE);
///////////////////////////////////////////////////////
// Convert volt to pwm
float dutycycleA = you_need_to_do;
float dutycycleB = you_need_to_do;
TIM1->CCR1 = CCR_value(dutycycleA); // this command will drive motorA
TIM1->CCR2 = CCR_value(dutycycleB); // this command will drive motorB
}
uint16_t CCR_value(float duty) {
// Convert PWM duty cycle to CCR (capture/compare register) value
return duty * uint16_t(TIM1->ARR);
}
void InitEncoder(void) {
// Hardware Quadrature Encoder AB for Nucleo F446RE
// Output on debug port to host PC @ 9600 baud
/* Connections
PA_0 = Encoder1 A
PA_1 = Encoder1 B
PB_5 = Encoder2 A
PB_4 = Encoder2 B
*/
// configure GPIO PA0, PA1, PB5 & PB4 as inputs for Encoder
RCC->AHB1ENR |= 0x00000003; // Enable clock for GPIOA & GPIOB
GPIOA->MODER |= GPIO_MODER_MODER0_1 | GPIO_MODER_MODER1_1 ; // PA0 & PA1 as Alternate Function /*!< GPIO port mode register, Address offset: 0x00 */
GPIOA->PUPDR |= GPIO_PUPDR_PUPDR0_0 | GPIO_PUPDR_PUPDR1_0 ; // Pull Down /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
GPIOA->AFR[0] |= 0x00000011 ; // AF1 for PA0 & PA1 /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
GPIOA->AFR[1] |= 0x00000000 ; // /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
GPIOB->MODER |= GPIO_MODER_MODER4_1 | GPIO_MODER_MODER5_1 ; // PB5 & PB4 as Alternate Function /*!< GPIO port mode register, Address offset: 0x00 */
GPIOB->PUPDR |= GPIO_PUPDR_PUPDR4_0 | GPIO_PUPDR_PUPDR5_0 ; // Pull Down /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
GPIOB->AFR[0] |= 0x00220000 ; // AF2 for PB5 & PB4 /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
GPIOB->AFR[1] |= 0x00000000 ; // /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
// configure TIM2 & TIM3 as Encoder input
RCC->APB1ENR |= 0x00000003; // Enable clock for TIM2 & TIM3
TIM2->CR1 = 0x0001; // CEN(Counter ENable)='1' < TIM control register 1
TIM2->SMCR = 0x0003; // SMS='011' (Encoder mode 3) < TIM slave mode control register
TIM2->CCMR1 = 0xF1F1; // CC1S='01' CC2S='01' < TIM capture/compare mode register 1
TIM2->CCMR2 = 0x0000; // < TIM capture/compare mode register 2
TIM2->CCER = 0x0011; // CC1P CC2P < TIM capture/compare enable register
TIM2->PSC = 0x0000; // Prescaler = (0+1) < TIM prescaler
TIM2->ARR = 0xffffffff; // reload at 0xfffffff < TIM auto-reload register
TIM2->CNT = 0x0000; //reset the counter before we use it
TIM3->CR1 = 0x0001; // CEN(Counter ENable)='1' < TIM control register 1
TIM3->SMCR = 0x0003; // SMS='011' (Encoder mode 3) < TIM slave mode control register
TIM3->CCMR1 = 0xF1F1; // CC1S='01' CC2S='01' < TIM capture/compare mode register 1
TIM3->CCMR2 = 0x0000; // < TIM capture/compare mode register 2
TIM3->CCER = 0x0011; // CC1P CC2P < TIM capture/compare enable register
TIM3->PSC = 0x0000; // Prescaler = (0+1) < TIM prescaler
TIM3->ARR = 0xffffffff; // reload at 0xfffffff < TIM auto-reload register
TIM3->CNT = 0x0000; //reset the counter before we use it
}