<すぐに使えるSTM32HAL!>GPIO、Delay、ADC_DMA、UART(自信ない)、UART_DMA(自信ない)、内部Timer、PWM(Duty・周期可変)、SPI(途中)、I2C(まだ)、エンコーダ(A相、B相)、CAN(まだ)、Teratermの設定、floatの有効化、インデント、入力補完
GPIO
/* USER CODE BEGIN 3 */
# 3.3V印加、1
HAL_GPIO_WritePin(GPIO1_GPIO_Port, GPIO1_Pin, GPIO_PIN_SET);
# 0V印加、0
HAL_GPIO_WritePin(GPIO1_GPIO_Port, GPIO1_Pin, GPIO_PIN_RESET);
# 3.3Vと0Vの切り替え
HAL_GPIO_TogglePin(GPIO1_GPIO_Port, GPIO1_Pin);
# 3.3Vか0Vの読み取り
HAL_GPIO_ReadPin(GPIO1_GPIO_Port, GPIO1_Pin)
Delay
# ms待つ
HAL_Delay(300);
ADC_DMA
#include "main.h"
#include "stdio.h"
#include "string.h"
/* USER CODE BEGIN 2 */
uint32_t adc_v[2] = {0}; /* 0 - 4096 */
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_v, 2);
HAL_Delay(1000);
char s[256]; //UART参照
/* USER CODE BEGIN 3 */
sprintf(s, "%5lu, %5lu\n\r", adc_v[0], adc_v[1]);
huart2.gState = HAL_UART_STATE_READY;
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)s, sizeof(s));
UART
#include "main.h"
#include "stdio.h"
#include "string.h"
/* USER CODE BEGIN 0 */
char s[256];
void send_uart(char *s){
HAL_UART_Transmit(&huart2, (uint8_t *) s, strlen(s), 2000);
}
/* USER CODE BEGIN 3 */
sprintf(buffer, "encorder = %d, CNT = %lu, DIR = %d\n", count_total, TIM1->CNT, (TIM1->CR1 >> 4) & 1 ? -1 : 1);
send_uart(buffer);
HAL_Delay(50);
UART_DMA
文字を送る場合。>>>%s
int >>> %d
int32_t >>> %ld
uint32_t>>>%lu
小数を送る場合。>>>%lf
DMA送信完了と同時にUARTのSTATEをREADYにする。
extern を忘れない
main.cでif文を書く。
内部Timer
これは変数の設定が終わってから、最後にスタートするべき。
84MHz/4200/20000=1Hzの設定(APB1orAPB2)
念のためにオシロスコープで確認しよう。
Interruptにチェックを入れるのを忘れずに。
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
HAL_Delay(1000);
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == htim2.Instance)
{
HAL_GPIO_TogglePin(GPIO1_GPIO_Port, GPIO1_Pin);
sprintf(s, "%5lu\n\r", i);
huart2.gState = HAL_UART_STATE_READY;
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)s, sizeof(s));
i++;
}
}
PWM(Duty比・周期可変)
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
/* USER CODE BEGIN 3 */
TIM2->CCR2 = 1000など;
TIM2->ARR = 2000-1など;
HAL_Delay(2000);
CCRxレジスタの値を変えれば、Duty比を変えられる。
ARRレジスタの値を変えれば、周期を変えられる。
100%のDutyを出すには、ARRレジスタの値よりCRRxレジスタの値が大きい必要があるとマニュアルに書かれてある。この例だと2000以上になる。
気になる場合は実際にオシロで確認するべき。
Duty比75%(ARR=1999、CRRx=1500)のとき
Duty比50%(ARR=1999、CRRx=1000)のとき
Duty比25%(ARR=1999、CRRx=500)のとき
周期の1/2(ARR=999、CRRx=500)のとき
周期の1/4(ARR=1999、CRRx=500)のとき
周期の1/8(ARR=3999、CRRx=500)のとき
SPI
SSがある場合、使用する前にhighからlowにする。
SCK以外は10kぐらいで必ずプルアップする。
MOSI--DI、MISO--DOに注意。
CPOL(Low)-->0
CPHA(1 Edge)-->0
アドレスと書き込み・読み込みの間にSSを挟むものと挟まないものがある。
I2C
Encorder
#include "main.h"
#include "stdio.h"
#include "string.h"
char buffer[1024];
void send_uart(char *s){
HAL_UART_Transmit(&huart2, (uint8_t *) s, strlen(s), 2000);
}
int16_t get_encoder(void)
{
static uint16_t count = 0;
int16_t difference = 0;
uint16_t nowcount = 0;
uint8_t direction = 0;
nowcount = TIM1->CNT;
direction = (TIM1->CR1 >> 4) & 1 ? -1 : 1;
if((nowcount*direction) < (count*direction)){
difference = nowcount - count + 65536*direction;
count = nowcount;
}else{
difference = nowcount - count;
count = nowcount;
}
return difference;
}
/* USER CODE BEGIN 2 */
int32_t count_total = 0;
HAL_TIM_Encoder_Start( &htim1, TIM_CHANNEL_ALL);
/* USER CODE BEGIN 3 */
count_total += get_encoder();
sprintf(buffer, "encorder = %d, CNT = %lu, DIR = %d\n", count_total, TIM1->CNT, (TIM1->CR1 >> 4) & 1 ? -1 : 1);
send_uart(buffer);
HAL_Delay(50);
1回転させて、表示される値がパルス数の4倍になればOKのはず。
向きが逆の場合は、プログラムの±を書き換えてください。
DIRには向きが入ると書いてある。
Teratermの設定
printfにおけるfloatの有効化
インデント
Window>Preferences>General>Editors>Text Editorsの
Displayed tab widthを変更する。
Window>Preferences>C/C++->Code Style->Formatter
Newで変更する。
どっち?
入力補完
入力補完は、「ctrlとspace」で出来る。