mirror of
https://github.com/eddyem/stm32samples.git
synced 2025-12-06 18:55:13 +03:00
add buttons, not tested yet
This commit is contained in:
parent
021c0bdf6b
commit
1ecea45cc0
121
F1:F103/CAR_CANbus/WindShield/buttons.c
Normal file
121
F1:F103/CAR_CANbus/WindShield/buttons.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the windshield project.
|
||||||
|
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stm32f1.h>
|
||||||
|
|
||||||
|
#include "buttons.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
|
||||||
|
extern volatile uint32_t Tms;
|
||||||
|
//uint32_t lastUnsleep = 0;
|
||||||
|
|
||||||
|
// threshold in ms for press/hold
|
||||||
|
#define PRESSTHRESHOLD (29)
|
||||||
|
// HOLDTHRESHOLD = PRESSTHRESHOLD + hold time
|
||||||
|
#define HOLDTHRESHOLD (329)
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
keyevent event; // current key event
|
||||||
|
int16_t counter; // press/release milliseconds counter
|
||||||
|
GPIO_TypeDef *port; // key port
|
||||||
|
uint16_t pin; // key pin
|
||||||
|
uint8_t changed; // the event have been changed
|
||||||
|
} keybase;
|
||||||
|
|
||||||
|
keybase allkeys[KEY_AMOUNT] = {
|
||||||
|
[HALL_D] = {.port = HALL_PORT, .pin = HALL_D_PIN},
|
||||||
|
[HALL_U] = {.port = HALL_PORT, .pin = HALL_U_PIN},
|
||||||
|
[KEY_D] = {.port = BUTTON_PORT, .pin = BUTTON_D_PIN},
|
||||||
|
[KEY_U] = {.port = BUTTON_PORT, .pin = BUTTON_U_PIN},
|
||||||
|
[DIR_D] = {.port = DIR_PORT, .pin = DIR_U_PIN},
|
||||||
|
[DIR_U] = {.port = DIR_PORT, .pin = DIR_U_PIN}
|
||||||
|
};
|
||||||
|
|
||||||
|
// return 1 if something was changed
|
||||||
|
int process_keys(){
|
||||||
|
static uint32_t lastT = 0;
|
||||||
|
int changed = FALSE;
|
||||||
|
if(Tms == lastT) return FALSE;
|
||||||
|
uint16_t d = (uint16_t)(Tms - lastT);
|
||||||
|
lastT = Tms;
|
||||||
|
for(int i = 0; i < KEY_AMOUNT; ++i){
|
||||||
|
keybase *k = &allkeys[i];
|
||||||
|
keyevent e = k->event;
|
||||||
|
if(PRESSED(k->port, k->pin)){ // key is in pressed state
|
||||||
|
//lastUnsleep = Tms; // update activity time (any key is in pressed state)
|
||||||
|
switch(e){
|
||||||
|
case EVT_NONE: // just pressed
|
||||||
|
case EVT_RELEASE:
|
||||||
|
k->counter = PRESSTHRESHOLD; // anti-bounce for released state
|
||||||
|
k->event = EVT_PRESS;
|
||||||
|
break;
|
||||||
|
case EVT_PRESS: // hold
|
||||||
|
if((k->counter += d)> HOLDTHRESHOLD)
|
||||||
|
k->event = EVT_HOLD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else{ // released
|
||||||
|
switch(e){
|
||||||
|
case EVT_PRESS: // count -> none
|
||||||
|
if(k->counter > PRESSTHRESHOLD) k->counter = PRESSTHRESHOLD;
|
||||||
|
else if((k->counter -= d) < 0) k->event = EVT_NONE; // button released
|
||||||
|
break;
|
||||||
|
case EVT_HOLD: // count -> release
|
||||||
|
if(k->counter > PRESSTHRESHOLD) k->counter = PRESSTHRESHOLD;
|
||||||
|
else if((k->counter -= d) < 0) k->event = EVT_RELEASE; // button released
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(e != k->event){
|
||||||
|
k->changed = 1;
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief keystate curent key state
|
||||||
|
* @param k - key code
|
||||||
|
* @param evt - its event
|
||||||
|
* @return 1 if event was changed since last call
|
||||||
|
*/
|
||||||
|
uint8_t keystate(keycode k, keyevent *evt){
|
||||||
|
if(k >= KEY_AMOUNT) return EVT_NONE;
|
||||||
|
*evt = allkeys[k].event;
|
||||||
|
// change state `release` to `none` after 1st check (or will be `changed` @ release -> none)
|
||||||
|
if(*evt == EVT_RELEASE) allkeys[k].event = EVT_NONE;
|
||||||
|
uint8_t r = allkeys[k].changed;
|
||||||
|
allkeys[k].changed = 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
keyevent keyevt(keycode k){
|
||||||
|
if(k >= KEY_AMOUNT) return EVT_NONE;
|
||||||
|
return allkeys[k].event;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear all `changed` states
|
||||||
|
void clear_events(){
|
||||||
|
for(int i = 0; i < KEY_AMOUNT; ++i)
|
||||||
|
allkeys[i].changed = 0;
|
||||||
|
}
|
||||||
50
F1:F103/CAR_CANbus/WindShield/buttons.h
Normal file
50
F1:F103/CAR_CANbus/WindShield/buttons.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the windshield project.
|
||||||
|
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stm32f1.h>
|
||||||
|
|
||||||
|
// long press detector (>99ms)
|
||||||
|
#define KEY_HOLDTIME (99)
|
||||||
|
|
||||||
|
// keycode for press/release
|
||||||
|
typedef enum{
|
||||||
|
HALL_D, // hall sensor DOWN
|
||||||
|
HALL_U, // -//- UP
|
||||||
|
KEY_D, // user key DOWN
|
||||||
|
KEY_U, // -//- UP
|
||||||
|
DIR_D, // ext signal (direct motor cables) DOWN
|
||||||
|
DIR_U, // -//- UP
|
||||||
|
KEY_AMOUNT // amount of keys connected
|
||||||
|
} keycode;
|
||||||
|
|
||||||
|
// events
|
||||||
|
typedef enum{
|
||||||
|
EVT_NONE, // no events with given key
|
||||||
|
EVT_PRESS, // pressed
|
||||||
|
EVT_HOLD, // hold more than KEY_HOLDTIME ms
|
||||||
|
EVT_RELEASE // released
|
||||||
|
} keyevent;
|
||||||
|
|
||||||
|
//extern uint32_t lastUnsleep; // last keys activity time
|
||||||
|
|
||||||
|
int process_keys();
|
||||||
|
void clear_events();
|
||||||
|
uint8_t keystate(keycode k, keyevent *evt);
|
||||||
|
keyevent keyevt(keycode k);
|
||||||
@ -16,6 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "buttons.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
|
|
||||||
/* pinout:
|
/* pinout:
|
||||||
@ -42,23 +43,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// last incr/decr time and minimal time between incr/decr CCRx
|
// last incr/decr time and minimal time between incr/decr CCRx
|
||||||
static uint32_t PWM_lasttime = 0, PWM_deltat = 1;
|
static uint32_t PWM_lasttime = 0, PWM_deltat = 1; // PWM_deltat should be more than timer period
|
||||||
static int direction = 0, accel = 0; // rotation direction and acceleration/deceleration
|
static int accel = 0; // rotation direction and acceleration/deceleration
|
||||||
|
static motdir_t direction = MOTDIR_NONE; // current moving direction
|
||||||
|
|
||||||
void gpio_setup(void){
|
void gpio_setup(void){
|
||||||
// PB8 & PB9 (CAN) setup in can.c; PA9 & PA10 (USART) in usart.c; PA6 & PA7 will be configured later
|
// PB8 & PB9 (CAN) setup in can.c; PA9 & PA10 (USART) in usart.c; PA6 & PA7 - TIM3 PWM ch1/2
|
||||||
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN;
|
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN;
|
||||||
// pullups & initial values
|
// pullups & initial values
|
||||||
GPIOA->ODR = (1<<11) | (1<<11) | (1<<12);
|
GPIOA->ODR = (1<<11) | (1<<12);
|
||||||
GPIOB->ODR = (1<<14) | (1<<15);
|
GPIOB->ODR = (1<<14) | (1<<15);
|
||||||
GPIOA->CRL = CRL(0, CNF_ANALOG) | CRL(1, CNF_PPOUTPUT|MODE_SLOW) | CRL(2, CNF_PPOUTPUT|MODE_SLOW) |
|
GPIOA->CRL = CRL(0, CNF_ANALOG) | CRL(1, CNF_PPOUTPUT|MODE_SLOW) | CRL(2, CNF_PPOUTPUT|MODE_SLOW) |
|
||||||
CRL(3, CNF_PPOUTPUT|MODE_SLOW);
|
CRL(3, CNF_PPOUTPUT|MODE_SLOW) | CRL(6, CNF_AFPP|MODE_FAST) | CRL(7, CNF_AFPP|MODE_FAST);
|
||||||
GPIOA->CRH = CRH(11, CNF_PUDINPUT) | CRH(12, CNF_PUDINPUT);
|
GPIOA->CRH = CRH(11, CNF_PUDINPUT) | CRH(12, CNF_PUDINPUT);
|
||||||
GPIOB->CRH = CRH(12, CNF_PUDINPUT) | CRH(13, CNF_PUDINPUT) | CRH(14, CNF_PUDINPUT) | CRH(15, CNF_PUDINPUT);
|
GPIOB->CRH = CRH(12, CNF_PUDINPUT) | CRH(13, CNF_PUDINPUT) | CRH(14, CNF_PUDINPUT) | CRH(15, CNF_PUDINPUT);
|
||||||
// setup timer: 100 ticks per full PWM range, 2kHz -> 200kHz timer frequency
|
// setup timer: 100 ticks per full PWM range, 2kHz -> 200kHz timer frequency
|
||||||
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // enable TIM3 clocking
|
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // enable TIM3 clocking
|
||||||
TIM3->CR1 = 0;
|
TIM3->CR1 = 0;
|
||||||
TIM3->PSC = (TIM3FREQ/PWMFREQ) - 1; // 359 ticks for 200kHz
|
TIM3->PSC = (TIM3FREQ/(PWMFREQ*PWMMAX)) - 1; // 359 ticks for 200kHz
|
||||||
TIM3->ARR = PWMMAX - 1;
|
TIM3->ARR = PWMMAX - 1;
|
||||||
TIM3->CCR1 = 0; // inactive
|
TIM3->CCR1 = 0; // inactive
|
||||||
TIM3->CCR2 = 0;
|
TIM3->CCR2 = 0;
|
||||||
@ -72,29 +74,32 @@ void gpio_setup(void){
|
|||||||
// set minimal pause between successive CCRx increments or decrements; return TRUE if OK
|
// set minimal pause between successive CCRx increments or decrements; return TRUE if OK
|
||||||
int set_dT(uint32_t d){
|
int set_dT(uint32_t d){
|
||||||
if(d > 1000) return FALSE;
|
if(d > 1000) return FALSE;
|
||||||
PWM_deltat = d;
|
PWM_deltat = d + 1;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop or start rotation in given direction (only if motor stops); return TRUE if OK
|
// stop or start rotation in given direction (only if motor stops); return TRUE if OK
|
||||||
// dir == 0 to stop; > 0 to rotate CW (L_UP, R_DOWN), < 0 to rotate CCW (L_DOWN, R_UP)
|
|
||||||
int motor_ctl(int32_t dir){
|
int motor_ctl(int32_t dir){
|
||||||
|
if(dir < MOTDIR_STOP || dir > MOTDIR_DOWN) return FALSE;
|
||||||
|
if(dir == MOTDIR_NONE) return TRUE;
|
||||||
|
if(direction == dir) return TRUE; // already do this
|
||||||
if(TIM3->CR1 & TIM_CR1_CEN){
|
if(TIM3->CR1 & TIM_CR1_CEN){
|
||||||
if(direction && dir) return FALSE; // motor is moving while trying to move it
|
if(direction > MOTDIR_NONE && dir > MOTDIR_NONE) return FALSE; // motor is moving while trying to move it into another dir
|
||||||
if(direction == 0 && dir == 0) return TRUE; // already stopped
|
if(direction == MOTDIR_BREAK && dir < MOTDIR_NONE) return TRUE; // already stopped
|
||||||
}
|
}
|
||||||
if(dir == 0){ // stop motor -> deceleration
|
if(dir == MOTDIR_STOP){ // stop motor -> deceleration
|
||||||
accel = -1;
|
if(direction == MOTDIR_UP || direction == MOTDIR_DOWN) accel = -1;
|
||||||
PWM_lasttime = Tms;
|
return TRUE;
|
||||||
|
}else if(dir == MOTDIR_BREAK){ // emergency stop
|
||||||
|
if(TIM3->CR1 & TIM_CR1_CEN) motor_break(); // break only if is moving
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
accel = 1;
|
accel = 1;
|
||||||
if(dir > 0){ // start in positive direction
|
direction = dir;
|
||||||
direction = 1;
|
if(dir == MOTDIR_UP){ // start in positive direction (move UP)
|
||||||
set_up(UP_LEFT);
|
set_up(UP_LEFT);
|
||||||
set_pwm(PWM_RIGHT, 1);
|
set_pwm(PWM_RIGHT, 1);
|
||||||
}else{ // negative
|
}else{ // negative (move DOWN)
|
||||||
direction = -1;
|
|
||||||
set_up(UP_RIGHT);
|
set_up(UP_RIGHT);
|
||||||
set_pwm(PWM_LEFT, 1);
|
set_pwm(PWM_LEFT, 1);
|
||||||
}
|
}
|
||||||
@ -106,33 +111,83 @@ int motor_ctl(int32_t dir){
|
|||||||
// extremal stop
|
// extremal stop
|
||||||
void motor_break(){
|
void motor_break(){
|
||||||
up_off();
|
up_off();
|
||||||
direction = 0; accel = 0;
|
direction = MOTDIR_BREAK;
|
||||||
|
accel = 0;
|
||||||
stop_pwm();
|
stop_pwm();
|
||||||
|
PWM_lasttime = Tms;
|
||||||
}
|
}
|
||||||
|
|
||||||
// simplest state machine of motor control
|
// simplest state machine of motor control
|
||||||
void motor_process(){
|
void motor_process(){
|
||||||
if(!direction) return; // motor isn't moving
|
if(process_keys()){ // check buttons
|
||||||
if(Tms - PWM_lasttime < PWM_deltat) return;
|
keyevent evt;
|
||||||
volatile uint16_t *CCRx = (direction > 0) ? &TIM3->CCR1 : &TIM3->CCR2; // current CCRx
|
motdir_t newdir = MOTDIR_NONE; // new moving direction (-2 - do nothing, 2 - emerg. stop)
|
||||||
if(accel < 0){ // decrement
|
// first, check HALL sensors if motor is moving
|
||||||
if(*CCRx == 0){ // stopped
|
if(direction){
|
||||||
up_off();
|
if(keystate(HALL_D, &evt)){ // HALL DOWN
|
||||||
direction = 0;
|
if(direction < 0 && (evt == EVT_PRESS || evt == EVT_HOLD)){
|
||||||
|
newdir = MOTDIR_BREAK;
|
||||||
|
}
|
||||||
|
}else if(keystate(HALL_U, &evt)){
|
||||||
|
if(direction > 0 && (evt == EVT_PRESS || evt == EVT_HOLD)){
|
||||||
|
newdir = MOTDIR_BREAK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyevent uh = keyevt(HALL_U), dh = keyevt(HALL_D); // current hall states - if we cannot move upper or lower
|
||||||
|
// short key pressed - full open/close; long - move with stop after release
|
||||||
|
if(MOTDIR_BREAK != newdir){ // process keys if don't need to break
|
||||||
|
evt = EVT_NONE;
|
||||||
|
if(keystate(KEY_U, &evt)){
|
||||||
|
if(evt == EVT_PRESS){ // move up (don't mind EVT_HOLD - it's already moving)
|
||||||
|
if(uh != EVT_HOLD && uh != EVT_PRESS) newdir = MOTDIR_UP;
|
||||||
|
}
|
||||||
|
}else if(keystate(KEY_D, &evt)){
|
||||||
|
if(evt == EVT_PRESS){
|
||||||
|
if(dh != EVT_HOLD && dh != EVT_PRESS) newdir = MOTDIR_DOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(evt == EVT_RELEASE) newdir = MOTDIR_STOP;
|
||||||
|
evt = EVT_NONE;
|
||||||
|
int extsig = FALSE;
|
||||||
|
// now chech external signals, they have an advantage over local keys
|
||||||
|
if(keystate(DIR_U, &evt)){ // react on PRESS and both NONE/RELEASE
|
||||||
|
extsig = TRUE;
|
||||||
|
if(evt == EVT_PRESS && uh != EVT_PRESS && uh != EVT_HOLD) newdir = MOTDIR_UP;
|
||||||
|
}else if(keystate(DIR_D, &evt)){
|
||||||
|
extsig = TRUE;
|
||||||
|
if(evt == EVT_PRESS && dh != EVT_PRESS && dh != EVT_HOLD) newdir = MOTDIR_DOWN;
|
||||||
|
}
|
||||||
|
if(evt == EVT_RELEASE || (extsig && evt == EVT_NONE)){ // EVT_NONE - released after short press - do nothing; EVT_RELEASE - after hold, stop
|
||||||
|
newdir = MOTDIR_STOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
motor_ctl(newdir);
|
||||||
|
clear_events();
|
||||||
|
}
|
||||||
|
if(direction == MOTDIR_NONE) return; // motor isn't moving
|
||||||
|
else if(direction == MOTDIR_BREAK && 0 == (TIM3->CR1 & TIM_CR1_CEN)){ // motor stopped
|
||||||
|
direction = MOTDIR_NONE;
|
||||||
accel = 0;
|
accel = 0;
|
||||||
stop_pwm();
|
return;
|
||||||
|
}
|
||||||
|
if(Tms < PWM_lasttime + PWM_deltat) return;
|
||||||
|
volatile uint16_t *CCRx = (direction > 0) ? &TIM3->CCR1 : &TIM3->CCR2; // current CCRx
|
||||||
|
PWM_lasttime = Tms;
|
||||||
|
if(accel < 0){ // deceleration
|
||||||
|
if(*CCRx == 0){ // stopped
|
||||||
|
motor_break(); // wait for another cycle
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: here we should check currents and if failure turn off immediatelly
|
// TODO: here we should check currents and if failure turn off immediatelly
|
||||||
--*CCRx;
|
--*CCRx;
|
||||||
}else{
|
}else{ // constant speed or acceleration
|
||||||
// TODO: here we should check currents and increment only if all OK; decrement and change to accel if fail
|
// TODO: here we should check currents and increment only if all OK; decrement and change to accel if fail
|
||||||
if(accel){ // acceleration
|
if(accel){ // acceleration
|
||||||
if(*CCRx == PWMMAX) accel = 0;
|
if(*CCRx == PWMMAX) accel = 0;
|
||||||
else ++*CCRx;
|
else ++*CCRx;
|
||||||
} // else do nothing - moving with constant speed
|
} // else do nothing - moving with constant speed
|
||||||
}
|
}
|
||||||
PWM_lasttime = Tms;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void iwdg_setup(){
|
void iwdg_setup(){
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
// frequency of TIM3 clocking
|
// frequency of TIM3 clocking
|
||||||
#define TIM3FREQ (72000000)
|
#define TIM3FREQ (72000000)
|
||||||
// PWM frequency
|
// PWM frequency
|
||||||
#define PWMFREQ (200000)
|
#define PWMFREQ (2000)
|
||||||
// max PWM value
|
// max PWM value
|
||||||
#define PWMMAX (100)
|
#define PWMMAX (100)
|
||||||
|
|
||||||
@ -44,7 +44,7 @@
|
|||||||
// turn off upper shoulders
|
// turn off upper shoulders
|
||||||
#define up_off() do{pin_clear(GPIOA, (1<<2)|(1<<3));}while(0)
|
#define up_off() do{pin_clear(GPIOA, (1<<2)|(1<<3));}while(0)
|
||||||
#define start_pwm() do{ TIM3->CR1 = TIM_CR1_CEN; TIM3->EGR |= TIM_EGR_UG; }while(0)
|
#define start_pwm() do{ TIM3->CR1 = TIM_CR1_CEN; TIM3->EGR |= TIM_EGR_UG; }while(0)
|
||||||
#define stop_pwm() do{ TIM3->CCR1 = 0; TIM3->CCR2 = 0; TIM3->CR1 = 0; }while(0)
|
#define stop_pwm() do{ TIM3->CCR1 = 0; TIM3->CCR2 = 0; TIM3->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; }while(0)
|
||||||
#define PWM_LEFT 2
|
#define PWM_LEFT 2
|
||||||
#define PWM_RIGHT 1
|
#define PWM_RIGHT 1
|
||||||
// set PWM value (0..100), x==1 - R_DOWN, x==2 - L_DOWN
|
// set PWM value (0..100), x==1 - R_DOWN, x==2 - L_DOWN
|
||||||
@ -53,6 +53,33 @@
|
|||||||
#define _get_pwm(x) (TIM3->CCR ## x)
|
#define _get_pwm(x) (TIM3->CCR ## x)
|
||||||
#define get_pwm(x) _get_pwm(x)
|
#define get_pwm(x) _get_pwm(x)
|
||||||
|
|
||||||
|
// buttons, dir, hall:
|
||||||
|
#define HALL_PORT GPIOA
|
||||||
|
#define HALL_U_PIN (1<<12)
|
||||||
|
#define HALL_D_PIN (1<<11)
|
||||||
|
#define BUTTON_PORT GPIOB
|
||||||
|
#define BUTTON_U_PIN (1<<14)
|
||||||
|
#define BUTTON_D_PIN (1<<15)
|
||||||
|
#define DIR_PORT GPIOB
|
||||||
|
#define DIR_U_PIN (1<12)
|
||||||
|
#define DIR_D_PIN (1<13)
|
||||||
|
|
||||||
|
// define BUTTONS_NEGATIVE if button pressed when ==1
|
||||||
|
#ifdef BUTTONS_NEGATIVE
|
||||||
|
#define PRESSED(port, pin) ((port->IDR & pin) == pin)
|
||||||
|
#else
|
||||||
|
#define PRESSED(port, pin) ((port->IDR & pin) == 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// moving when > NONE, stopped when < NONE
|
||||||
|
typedef enum{
|
||||||
|
MOTDIR_STOP = -2, // stop with deceleration
|
||||||
|
MOTDIR_BREAK = -1, // emergency stop
|
||||||
|
MOTDIR_NONE = 0, // do nothing
|
||||||
|
MOTDIR_UP = 1, // move up
|
||||||
|
MOTDIR_DOWN = 2, // move down
|
||||||
|
} motdir_t;
|
||||||
|
|
||||||
int set_dT(uint32_t d);
|
int set_dT(uint32_t d);
|
||||||
|
|
||||||
extern volatile uint32_t Tms;
|
extern volatile uint32_t Tms;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -67,11 +67,30 @@
|
|||||||
"visible_layers": "fffffff_ffffffff",
|
"visible_layers": "fffffff_ffffffff",
|
||||||
"zone_display_mode": 1
|
"zone_display_mode": 1
|
||||||
},
|
},
|
||||||
|
"git": {
|
||||||
|
"repo_password": "",
|
||||||
|
"repo_type": "",
|
||||||
|
"repo_username": "",
|
||||||
|
"ssh_key": ""
|
||||||
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"filename": "windshield.kicad_prl",
|
"filename": "windshield.kicad_prl",
|
||||||
"version": 3
|
"version": 3
|
||||||
},
|
},
|
||||||
"project": {
|
"project": {
|
||||||
"files": []
|
"files": []
|
||||||
|
},
|
||||||
|
"schematic": {
|
||||||
|
"selection_filter": {
|
||||||
|
"graphics": true,
|
||||||
|
"images": true,
|
||||||
|
"labels": true,
|
||||||
|
"lockedItems": false,
|
||||||
|
"otherItems": true,
|
||||||
|
"pins": true,
|
||||||
|
"symbols": true,
|
||||||
|
"text": true,
|
||||||
|
"wires": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -194,6 +194,13 @@
|
|||||||
],
|
],
|
||||||
"zones_allow_external_fillets": false
|
"zones_allow_external_fillets": false
|
||||||
},
|
},
|
||||||
|
"ipc2581": {
|
||||||
|
"dist": "",
|
||||||
|
"distpn": "",
|
||||||
|
"internal_id": "",
|
||||||
|
"mfg": "",
|
||||||
|
"mpn": ""
|
||||||
|
},
|
||||||
"layer_presets": [],
|
"layer_presets": [],
|
||||||
"viewports": []
|
"viewports": []
|
||||||
},
|
},
|
||||||
@ -388,10 +395,12 @@
|
|||||||
"duplicate_sheet_names": "error",
|
"duplicate_sheet_names": "error",
|
||||||
"endpoint_off_grid": "warning",
|
"endpoint_off_grid": "warning",
|
||||||
"extra_units": "error",
|
"extra_units": "error",
|
||||||
|
"footprint_link_issues": "warning",
|
||||||
"global_label_dangling": "warning",
|
"global_label_dangling": "warning",
|
||||||
"hier_label_mismatch": "error",
|
"hier_label_mismatch": "error",
|
||||||
"label_dangling": "error",
|
"label_dangling": "error",
|
||||||
"lib_symbol_issues": "warning",
|
"lib_symbol_issues": "warning",
|
||||||
|
"lib_symbol_mismatch": "warning",
|
||||||
"missing_bidi_pin": "warning",
|
"missing_bidi_pin": "warning",
|
||||||
"missing_input_pin": "warning",
|
"missing_input_pin": "warning",
|
||||||
"missing_power_pin": "error",
|
"missing_power_pin": "error",
|
||||||
@ -452,14 +461,75 @@
|
|||||||
"gencad": "",
|
"gencad": "",
|
||||||
"idf": "",
|
"idf": "",
|
||||||
"netlist": "",
|
"netlist": "",
|
||||||
|
"plot": "",
|
||||||
|
"pos_files": "",
|
||||||
"specctra_dsn": "",
|
"specctra_dsn": "",
|
||||||
"step": "",
|
"step": "",
|
||||||
|
"svg": "",
|
||||||
"vrml": ""
|
"vrml": ""
|
||||||
},
|
},
|
||||||
"page_layout_descr_file": ""
|
"page_layout_descr_file": ""
|
||||||
},
|
},
|
||||||
"schematic": {
|
"schematic": {
|
||||||
"annotate_start_num": 0,
|
"annotate_start_num": 0,
|
||||||
|
"bom_fmt_presets": [],
|
||||||
|
"bom_fmt_settings": {
|
||||||
|
"field_delimiter": ",",
|
||||||
|
"keep_line_breaks": false,
|
||||||
|
"keep_tabs": false,
|
||||||
|
"name": "CSV",
|
||||||
|
"ref_delimiter": ",",
|
||||||
|
"ref_range_delimiter": "",
|
||||||
|
"string_delimiter": "\""
|
||||||
|
},
|
||||||
|
"bom_presets": [],
|
||||||
|
"bom_settings": {
|
||||||
|
"exclude_dnp": false,
|
||||||
|
"fields_ordered": [
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Reference",
|
||||||
|
"name": "Reference",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Value",
|
||||||
|
"name": "Value",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Datasheet",
|
||||||
|
"name": "Datasheet",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Footprint",
|
||||||
|
"name": "Footprint",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Qty",
|
||||||
|
"name": "${QUANTITY}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "DNP",
|
||||||
|
"name": "${DNP}",
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filter_string": "",
|
||||||
|
"group_symbols": true,
|
||||||
|
"name": "Grouped By Value",
|
||||||
|
"sort_asc": true,
|
||||||
|
"sort_field": "Reference"
|
||||||
|
},
|
||||||
|
"connection_grid_size": 50.0,
|
||||||
"drawing": {
|
"drawing": {
|
||||||
"dashed_lines_dash_length_ratio": 12.0,
|
"dashed_lines_dash_length_ratio": 12.0,
|
||||||
"dashed_lines_gap_length_ratio": 3.0,
|
"dashed_lines_gap_length_ratio": 3.0,
|
||||||
@ -473,6 +543,11 @@
|
|||||||
"intersheets_ref_suffix": "",
|
"intersheets_ref_suffix": "",
|
||||||
"junction_size_choice": 3,
|
"junction_size_choice": 3,
|
||||||
"label_size_ratio": 0.375,
|
"label_size_ratio": 0.375,
|
||||||
|
"operating_point_overlay_i_precision": 3,
|
||||||
|
"operating_point_overlay_i_range": "~A",
|
||||||
|
"operating_point_overlay_v_precision": 3,
|
||||||
|
"operating_point_overlay_v_range": "~V",
|
||||||
|
"overbar_offset_ratio": 1.23,
|
||||||
"pin_symbol_size": 25.0,
|
"pin_symbol_size": 25.0,
|
||||||
"text_offset_ratio": 0.15
|
"text_offset_ratio": 0.15
|
||||||
},
|
},
|
||||||
@ -488,6 +563,7 @@
|
|||||||
"spice_external_command": "spice \"%I\"",
|
"spice_external_command": "spice \"%I\"",
|
||||||
"spice_model_current_sheet_as_root": true,
|
"spice_model_current_sheet_as_root": true,
|
||||||
"spice_save_all_currents": false,
|
"spice_save_all_currents": false,
|
||||||
|
"spice_save_all_dissipations": false,
|
||||||
"spice_save_all_voltages": false,
|
"spice_save_all_voltages": false,
|
||||||
"subpart_first_id": 65,
|
"subpart_first_id": 65,
|
||||||
"subpart_id_separator": 0
|
"subpart_id_separator": 0
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
BIN
F1:F103/CAR_CANbus/WindShield/kicad/windshield.pdf
Normal file
BIN
F1:F103/CAR_CANbus/WindShield/kicad/windshield.pdf
Normal file
Binary file not shown.
@ -32,10 +32,12 @@ const char *helpmsg =
|
|||||||
"https://github.com/eddyem/stm32samples/tree/master/F1:F103/CAR_CANbus/WindShield build#" BUILD_NUMBER " @ " BUILD_DATE "\n"
|
"https://github.com/eddyem/stm32samples/tree/master/F1:F103/CAR_CANbus/WindShield build#" BUILD_NUMBER " @ " BUILD_DATE "\n"
|
||||||
"'0' - stop PWM\n"
|
"'0' - stop PWM\n"
|
||||||
"'1' - start PWM\n"
|
"'1' - start PWM\n"
|
||||||
|
"'a' - RAW ADC values\n"
|
||||||
"'b' - break motor (extremal stop)\n"
|
"'b' - break motor (extremal stop)\n"
|
||||||
|
"'f' - set PWM freq (Hz)\n"
|
||||||
"'d xx' - set dT to xx ms\n"
|
"'d xx' - set dT to xx ms\n"
|
||||||
"'m xx' - move motor right (1), left (-1) or stop (0)\n"
|
"'m xx' - move motor up (1), down (2), stop (-2) or emerg stop (-1)\n"
|
||||||
"'p y xx' - set PWM y (l/r) to xx (0..100)"
|
"'p y xx' - set PWM y (l/r) to xx (0..100)\n"
|
||||||
"'s' - get raw VSEN value\n"
|
"'s' - get raw VSEN value\n"
|
||||||
"'t' - get MCU temperature (*10)\n"
|
"'t' - get MCU temperature (*10)\n"
|
||||||
"'u y xx' - turn on (xx==1) or off (xx==0) y (l/r) MOSFET\n"
|
"'u y xx' - turn on (xx==1) or off (xx==0) y (l/r) MOSFET\n"
|
||||||
@ -115,27 +117,38 @@ static int startPWM(){
|
|||||||
*/
|
*/
|
||||||
void cmd_parser(char *txt){
|
void cmd_parser(char *txt){
|
||||||
char _1st = txt[0];
|
char _1st = txt[0];
|
||||||
txt = (char*)omit_spaces(txt + 1);
|
/* usart_send("Got: '");
|
||||||
|
usart_send(txt);
|
||||||
|
usart_send("'\n");*/
|
||||||
|
char *nxtsym = (char*)omit_spaces(txt + 1);
|
||||||
|
uint32_t N = 0;
|
||||||
int proc = 1;
|
int proc = 1;
|
||||||
switch(_1st){ // parse long commands here
|
switch(_1st){ // parse long commands here
|
||||||
case 'd':
|
case 'd':
|
||||||
usetter(set_dT, txt);
|
usetter(set_dT, nxtsym);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
if(nxtsym != getnum(nxtsym, &N)){
|
||||||
|
if(N < 100 || N > 100000) usart_send("100 <= F <= 100000");
|
||||||
|
else TIM3->PSC = (TIM3FREQ/(N*PWMMAX)) - 1;
|
||||||
|
}
|
||||||
|
usart_send("TIM3->PSC="); usart_send(u2str(TIM3->PSC));
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
isetter(motor_ctl, txt);
|
isetter(motor_ctl, nxtsym);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
if(setdir(*txt)){
|
if(setdir(*nxtsym)){
|
||||||
txt = (char*)omit_spaces(txt + 1);
|
nxtsym = (char*)omit_spaces(nxtsym + 1);
|
||||||
usetter(pwmvalsetter, txt); newline();
|
usetter(pwmvalsetter, nxtsym); newline();
|
||||||
}
|
}
|
||||||
usart_send("PWM1="); usart_send(u2str(get_pwm(PWM_RIGHT)));
|
usart_send("PWM1="); usart_send(u2str(get_pwm(PWM_RIGHT)));
|
||||||
usart_send("\nPWM2="); usart_send(u2str(get_pwm(PWM_LEFT)));
|
usart_send("\nPWM2="); usart_send(u2str(get_pwm(PWM_LEFT)));
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
if(setdir(*txt)){
|
if(setdir(*nxtsym)){
|
||||||
txt = (char*)omit_spaces(txt + 1);
|
nxtsym = (char*)omit_spaces(nxtsym + 1);
|
||||||
usetter(upsetter, txt); newline();
|
usetter(upsetter, nxtsym); newline();
|
||||||
}
|
}
|
||||||
usart_send("UPL="); usart_putchar('0' + read_upL());
|
usart_send("UPL="); usart_putchar('0' + read_upL());
|
||||||
usart_send("\nUPR="); usart_putchar('0' + read_upR());
|
usart_send("\nUPR="); usart_putchar('0' + read_upR());
|
||||||
@ -153,6 +166,13 @@ void cmd_parser(char *txt){
|
|||||||
case '1':
|
case '1':
|
||||||
printans(startPWM());
|
printans(startPWM());
|
||||||
break;
|
break;
|
||||||
|
case 'a':
|
||||||
|
for(int i = 0; i < NUMBER_OF_ADC_CHANNELS; ++i){
|
||||||
|
usart_send("ADC"); usart_putchar('0' + i);
|
||||||
|
usart_putchar('='); usart_send(u2str(getADCval(i)));
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
motor_break(); printans(TRUE);
|
motor_break(); printans(TRUE);
|
||||||
break;
|
break;
|
||||||
@ -172,11 +192,11 @@ void cmd_parser(char *txt){
|
|||||||
else usart_send("OFF");
|
else usart_send("OFF");
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
usart_send("Soft reset\n");
|
usart_send("Soft reset\n\n");
|
||||||
usart_transmit();
|
usart_transmit();
|
||||||
// wait until DMA & USART done
|
// wait until DMA & USART done
|
||||||
while(!usart_txrdy);
|
while(!usart_txrdy);
|
||||||
while(!(USART1->SR & USART_SR_TXE));
|
while(!(USART1->SR & USART_SR_TC));
|
||||||
USART1->CR1 = 0; // stop USART
|
USART1->CR1 = 0; // stop USART
|
||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -114,7 +114,7 @@ void usart_setup(){
|
|||||||
NVIC_EnableIRQ(DMA1_Channel4_IRQn);
|
NVIC_EnableIRQ(DMA1_Channel4_IRQn);
|
||||||
NVIC_SetPriority(USART1_IRQn, 0);
|
NVIC_SetPriority(USART1_IRQn, 0);
|
||||||
// setup usart1
|
// setup usart1
|
||||||
USART1->BRR = 72000000 / 921600;
|
USART1->BRR = 72000000 / 115200;
|
||||||
USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART
|
USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART
|
||||||
while(!(USART1->SR & USART_SR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission
|
while(!(USART1->SR & USART_SR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission
|
||||||
USART1->SR = 0; // clear flags
|
USART1->SR = 0; // clear flags
|
||||||
|
|||||||
@ -19,8 +19,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// input and output buffers size
|
// input and output buffers size
|
||||||
#define UARTBUFSZI (256)
|
#define UARTBUFSZI (64)
|
||||||
#define UARTBUFSZO (1024)
|
#define UARTBUFSZO (128)
|
||||||
|
|
||||||
#define usartrx() (usart_linerdy)
|
#define usartrx() (usart_linerdy)
|
||||||
#define usartovr() (usart_bufovr)
|
#define usartovr() (usart_bufovr)
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
#define BUILD_NUMBER "10"
|
#define BUILD_NUMBER "21"
|
||||||
#define BUILD_DATE "2024-02-13"
|
#define BUILD_DATE "2024-03-04"
|
||||||
|
|||||||
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE QtCreatorProject>
|
<!DOCTYPE QtCreatorProject>
|
||||||
<!-- Written by QtCreator 12.0.2, 2024-02-12T22:44:46. -->
|
<!-- Written by QtCreator 12.0.2, 2024-03-04T19:10:32. -->
|
||||||
<qtcreator>
|
<qtcreator>
|
||||||
<data>
|
<data>
|
||||||
<variable>EnvironmentId</variable>
|
<variable>EnvironmentId</variable>
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
adc.c
|
adc.c
|
||||||
adc.h
|
adc.h
|
||||||
|
buttons.c
|
||||||
|
buttons.h
|
||||||
can.c
|
can.c
|
||||||
can.h
|
can.h
|
||||||
flash.c
|
flash.c
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user