前言:
学习于电子设计工坊;
本片笔记记录扩展版外设基础的配置和使用;
备赛ing;
比赛准备流程:
1.math.h包含下列头文件
一、数码管显示
1、程序设计
1)P3和P4的SER,RCK,SCK短接;
2)PA1,PA2,PA3为推挽输出;
3)编写seg.c和seg.h文件;
a.复制共阴极数码管段码;
b. 编写seg.c和seg.h文件;
/* 1.宏定义引脚 */
#define SER_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET)
#define SER_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET)
#define SCK_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET)
#define SCK_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET)
#define RCK_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET)
#define RCK_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET)
/* 2.定时显示数组 */
u8 seg_buf[3]; //数码管显示缓存数组
u8 seg_code[]={ //共阴段码表
// 0 1 2 3 4 5 6 7 8 9
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F
};
/* 3.编写显示函数 */
void Seg_Display(void)
{
u8 i;
for(i=0; i<8; i++)
{
if(seg_buf[2] & 0x80) SER_H;
else SER_L;
SCK_L; //触发移位
SCK_H;
seg_buf[2] <<= 1;
}
for(i=0; i<8; i++)
{
if(seg_buf[1] & 0x80) SER_H;
else SER_L;
SCK_L;
SCK_H;
seg_buf[1] <<= 1;
}
for(i=0; i<8; i++)
{
if(seg_buf[0] & 0x80) SER_H;
else SER_L;
SCK_L;
SCK_H;
seg_buf[0] <<= 1;
}
RCK_L; //触发并行输出
RCK_H;
}
c.主函数编写Process;
__IO u32 segTick;
u16 segcnt;
void SEG_Process(void)
{
if(uwTick -segTick < 100) return;
segTick=uwTick ;
//显示缓存赋值
segcnt++;
seg_buf[0]=seg_code[segcnt/100];
seg_buf[1]=seg_code[segcnt/10%10];
seg_buf[2]=seg_code[segcnt%10];
//数码管显示
Seg_Display();
//其他
// seg_buf[0]=seg_code[segcnt/100] | 0x80; //点亮小数点
// seg_buf[0]=seg_code[segcnt/100] & 0x00; //全灭
}
2、知识点概括
1)移位时钟不需要进行延迟,因为逻辑芯片的工作频率很高;
2)代码中要先发送最高位,即第三个数码管的最高位数据;
3、电路图
PA1- SER;PA2 - RCLK;PA3 - SER;
二、ADC双路采集
1、程序设计
1)P4和P3的AO1、AO2短接;
2)PA4,PA5为ADC采集模式,并为单端模式;
3)配置ADC的转换通道数、RANK、速度(取MAX,容错率高);
a.主函数编写Process;
float adc2_rp5_vol,adc2_rp6_vol;
void ADC_Process(void)
{
//RANK1 - ADC2_IN13 - RP6 - PA5
HAL_ADC_Start(&hadc2);
adc2_rp6_vol = HAL_ADC_GetValue(&hadc2) / 4095.0f * 3.3f;
//RANK2 - ADC2_IN17 - RP5 - PA4
HAL_ADC_Start(&hadc2);
adc2_rp5_vol = HAL_ADC_GetValue(&hadc2) / 4095.0f * 3.3f;
}
2、知识点概括
1)ADC为12位,分辨率为0-4095;
3、电路图
PA4- AO1;PA5 - AO2;
三、光敏电阻 (Photo)
1、程序设计
1)P4和P5的TRDO、TRAO短接;
2)PA4为ADC采集模式,并为单端模式;
4)PA3为GPIO输入模式,读取TRDP的电平;
a.主函数编写Process;
float adc2_rp5_vol,adc2_rp6_vol;
void ADC_Process(void)
{
//RANK1 - ADC2_IN13 - RP6 - PA5
HAL_ADC_Start(&hadc2);
adc2_rp6_vol = HAL_ADC_GetValue(&hadc2) / 4095.0f * 3.3f;
//RANK2 - ADC2_IN17 - 光敏电阻 - PA4
HAL_ADC_Start(&hadc2);
adc2_rp5_vol = HAL_ADC_GetValue(&hadc2) / 4095.0f * 3.3f;
}
_Bool trdo; //获取比较输出值
void Photo_Process(void)
{
trdo = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3);
}
2、知识点概括
1)光线越亮,光敏电阻的电阻值越大,TRAO的电压越大;
2)光线越暗,光敏电阻的电阻值越小,TRAO的电压越小;
3)LM393电压比较器:V+ > V- ,输出3.3V;
V+ < V- ,输出0;
V+(3引脚), V-(2引脚);
TRDO输出为开漏输出,需要外接上拉电阻;
其输出就只有两种情况,3.3V和0;
3、电路图
PA3 - TrDO;PA4 - TrAO;
四、ADC按键
1、程序设计
1)P4和P5的ADC_KEY短接;
2)PA5为ADC采集模式,并为单端模式;
a.主函数编写ADC_Process;获取采样值;
u16 adc2_akey_value;
float adc2_rp5_vol,adc2_rp6_vol;
void ADC_Process(void)
{
//RANK1 - ADC2_IN13 - ADC按键 - PA4
HAL_ADC_Start(&hadc2);
adc2_akey_value = HAL_ADC_GetValue(&hadc2);
//RANK2 - ADC2_IN17 - RP5 - PA5
HAL_ADC_Start(&hadc2);
adc2_rp5_vol = HAL_ADC_GetValue(&hadc2) / 4095.0f * 3.3f;
}
b.编写ADC_Key_IO;根据采样值判断哪个按键按下;
u8 ADC_Key_IO(void)
{
u8 keyio = 0x00;
if(adc2_akey_value < 200)
keyio |= 0x01;
else if(adc2_akey_value < 800)
keyio |= 0x02;
else if(adc2_akey_value < 1400)
keyio |= 0x04;
else if(adc2_akey_value < 2000)
keyio |= 0x08;
else if(adc2_akey_value < 2600)
keyio |= 0x10;
else if(adc2_akey_value < 3200)
keyio |= 0x20;
else if(adc2_akey_value < 3800)
keyio |= 0x40;
else if(adc2_akey_value < 3950)
keyio |= 0x80;
return keyio;
}
c.编写三行按键法;可实现单次触发和长按判断;
u8 AKEY_Trg; //单次触发
u8 AKEY_Cont; //长按
void AKey_Read(void)
{
u8 ReadData = ADC_Key_IO();
AKEY_Trg = ReadData & (ReadData ^ AKEY_Cont);
AKEY_Cont = ReadData;
}
d.编写AKEY_Process;
__IO u32 akeyTick;
u8 akey_cnt;
void AKEY_Process(void)
{
if(uwTick - akeyTick < 20) return;
akeyTick = uwTick;
AKey_Read();
//短按 S1
if(AKEY_Trg & 0x01)
{
segcnt++;
}
//长按 S2
if(AKEY_Cont & 0x02)
{
akey_cnt++;
}
if((AKEY_Cont == 0x00) && (AKEY_Trg == 0x00))
{
if(akey_cnt > 50)
{
segcnt++;
akey_cnt = 0;
}
else if(akey_cnt != 0)
akey_cnt = 0;
}
}
2、知识点概括
1)转换值:4095 * 电阻值 / (10k + 电阻值)
2)原理:不同按键按下时,对应的分压电阻值不同,即采集到的电压值不同;
3)新板子和旧版子的分压电阻值不同,比赛时要具体判断;
3、电路图
PA5 - ADC_KEY;
五、DS18B20
1、程序设计
1)P4和P5的TDQ短接;(Temp Data Query);P2的6不要短接;
2)移植驱动库ds18b20_hal.h、ds18b20_hal.c;
a.编写DS18B20读写函数;
float DS18B20_Read(void)
{
float temp_return;
u8 low,high;
ow_reset(); //复位
ow_byte_wr(0xcc); //跳过ROM
ow_byte_wr(0x44); //启动温度转换
ow_reset(); //复位
ow_byte_wr(0xcc); //跳过ROM
ow_byte_wr(0xbe); //读取寄存器
low = ow_byte_rd();
high = ow_byte_rd();
temp_return = (high << 8 | low) * 0.0625; //分辨率为12位,每个1为0.0625
return temp_return;
}
b.修改ds18b20_hal.c中的延时 ;
#define delay_us(X) delay((X)*100/5);
c.主函数编写进程;
__IO u32 ds18b20Tick;
float temp_float;
void DS18B20_Process(void)
{
if(uwTick - ds18b20Tick < 500)return;
ds18b20Tick = uwTick;
temp_float = DS18B20_Read();
}
d.解决上电85℃的问题;
在main的while(1)前面添加:
while((u16)DS18B20_Read() == 85 ));
若模块损坏,有可能卡在初始化,我感觉这样子不太好;
2、知识点概括
1)通信流程和通信方式打算专门写一篇文章;
3、电路图
六、DHT11
1、程序设计
1)P4和P3的HDQ短接;(Humidity Data Query);P2的7不要短接;
2)移植驱动库dht11.h、dht11.c;
a.依据ds18b20_hal.h、ds18b20_hal.c修改dht11.h、dht11.c,转为hal库的代码;
主要修改dht11_init()、mode_input()、mode_output();
dht11_read()函数修改函数用到:HAL_GPIO_WritePin();HAL_GPIO_ReadPin();
b.修改dht11.c中的延时 ;
#define delay_us(X) delay((X)*100/5)
c.主函数编写进程;
__IO u32 dht11Tick;
u32 dht11_val;
void DHT11_Process(void)
{
if(uwTick - dht11Tick < 600)return;
dht11Tick = uwTick;
dht11_val = dht11_read();
}
2、知识点概括
1)通信流程和通信方式打算专门写一篇文章;
3、电路图
七、一个定时器测两路PWM频率
1、程序设计
1)P4和P5的PULS1、PULS2短接;
2)PA1和PA2的GPIO为如下模式;
3)模式配置:
设置CNT每1us+1;
使能NVIC中断;
a.复制代码;
代码路径:stm32cube_fw_g4_v120\STM32Cube_FW_G4_V1.2.0\Projects\NUCLEO-G431RB\Examples\TIM\TIM_InputCapture;
b.修改代码内容;
①变量名 -> 变量名_TxCHy;(所有变量)
②HAL_TIM_ACTIVE_CHANNEL_x,修改x通道;
③TIM_CHANNEL_x,修改x通道;
④uwDiffCapture_T2CH3 = ((0xFFFF - uwIC2Value1_T2CH3) + uwIC2Value2_T2CH3) + 1;
修改0xFFFF,修改为该定时器最大的计数值;
⑤uwFrequency_T2CH3 = HAL_RCC_GetPCLK2Freq() / uwDiffCapture_T2CH3; //计算频率
修改HAL_RCC_GetPCLK2Freq()为1e6,即1000 000;
c.主函数开启定时器中断;
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
d.最终代码变量;
/* Captured Values */
/* TIM2_CH2 -> RP3 */
uint32_t uwIC2Value1_T2CH2 = 0;
uint32_t uwIC2Value2_T2CH2 = 0;
uint32_t uwDiffCapture_T2CH2 = 0;
/* Capture index */
uint16_t uhCaptureIndex_T2CH2 = 0;
/* Frequency Value */
uint32_t uwFrequency_T2CH2 = 0;
/* Captured Values */
/* TIM2_CH3 -> RP4 */
uint32_t uwIC2Value1_T2CH3 = 0;
uint32_t uwIC2Value2_T2CH3 = 0;
uint32_t uwDiffCapture_T2CH3 = 0;
/* Capture index */
uint16_t uhCaptureIndex_T2CH3 = 0;
/* Frequency Value */
uint32_t uwFrequency_T2CH3 = 0;
e.最终代码内容;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3) //TIM2_CH3
{
if(uhCaptureIndex_T2CH3 == 0)
{
/* Get the 1st Input Capture value */
uwIC2Value1_T2CH3 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
uhCaptureIndex_T2CH3 = 1;
}
else if(uhCaptureIndex_T2CH3 == 1) //获取两次上升沿之间的间隔
{
/* Get the 2nd Input Capture value */
uwIC2Value2_T2CH3 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
/* Capture computation */
if (uwIC2Value2_T2CH3 > uwIC2Value1_T2CH3)
{
uwDiffCapture_T2CH3 = (uwIC2Value2_T2CH3 - uwIC2Value1_T2CH3);
}
else if (uwIC2Value2_T2CH3 < uwIC2Value1_T2CH3)
{
/* 0xFFFF is max TIM1_CCRx value */
uwDiffCapture_T2CH3 = ((0xFFFFFFFF - uwIC2Value1_T2CH3) + uwIC2Value2_T2CH3) + 1;
}
/* Frequency computation: for this example TIMx (TIM1) is clocked by
APB2Clk */
uwFrequency_T2CH3 = 1e6 / uwDiffCapture_T2CH3; //计算频率
uhCaptureIndex_T2CH3 = 0;
}
}
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) //TIM2_CH2
{
if(uhCaptureIndex_T2CH2 == 0)
{
/* Get the 1st Input Capture value */
uwIC2Value1_T2CH2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
uhCaptureIndex_T2CH2 = 1;
}
else if(uhCaptureIndex_T2CH2 == 1) //获取两次上升沿之间的间隔
{
/* Get the 2nd Input Capture value */
uwIC2Value2_T2CH2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
/* Capture computation */
if (uwIC2Value2_T2CH2 > uwIC2Value1_T2CH2)
{
uwDiffCapture_T2CH2 = (uwIC2Value2_T2CH2 - uwIC2Value1_T2CH2);
}
else if (uwIC2Value2_T2CH2 < uwIC2Value1_T2CH2)
{
/* 0xFFFF is max TIM1_CCRx value */
uwDiffCapture_T2CH2 = ((0xFFFFFFFF - uwIC2Value1_T2CH2) + uwIC2Value2_T2CH2) + 1;
}
/* Frequency computation: for this example TIMx (TIM1) is clocked by
APB2Clk */
uwFrequency_T2CH2 = 1e6 / uwDiffCapture_T2CH2; //计算频率
uhCaptureIndex_T2CH2 = 0;
}
}
}
}
2、知识点概括
1)通过获取CCR寄存器的值,来得到两次上升沿之间的时间,进而计算出频率;
2)回调函数中,要进行具体判断是哪一个定时器,在具体判断时哪一个通道;
3)原函数中的Error_Handler()用不到可以进行删除;
3、电路图
八、一个定时器测两路PWM频率和占空比
1、程序设计
1)P4和P5的PWM1、PWM2短接;P2的6、7不要短接;
2)PA6和PA7的GPIO为如下模式;
3)模式配置:
与《七、一个定时器测两路PWM频率》相同;
a.复制代码;
代码路径:stm32cube_fw_g4_v120\STM32Cube_FW_G4_V1.2.0\Projects\NUCLEO-G431RB\Examples\TIM\TIM_InputCapture;
b.修改代码内容;
c.主函数开启定时器中断;
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_2);
d.最终代码变量;
/* Captured Values */
uint32_t uwIC1Value1_T3CH1 = 0;
uint32_t uwIC1Value2_T3CH1 = 0;
uint32_t uwHigh_T3CH1 = 0, uwLow_T3CH1 = 0; //高电平、低电平计数时间
float duty_T3CH1 = 0;
/* Capture index */
uint16_t uhCaptureIndex_T3CH1 = 0;
/* Frequency Value */
uint32_t uwFrequency_T3CH1 = 0;
/* Captured Values */
uint32_t uwIC2Value1_T3CH2 = 0;
uint32_t uwIC2Value2_T3CH2 = 0;
uint32_t uwHigh_T3CH2 = 0, uwLow_T3CH2 = 0; //高电平、低电平计数时间
float duty_T3CH2 = 0;
/* Capture index */
uint16_t uhCaptureIndex_T3CH2 = 0;
/* Frequency Value */
uint32_t uwFrequency_T3CH2 = 0;
e.最终代码内容;
//TIM3
if(htim->Instance == TIM3)
{
//TIM3_CH1
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
if(uhCaptureIndex_T3CH1 == 0) //第一次中断:上升沿中断,CCR
{
/* Get the 1st Input Capture value */
uwIC1Value1_T3CH1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);
uhCaptureIndex_T3CH1 = 1;
}
else if(uhCaptureIndex_T3CH1 == 1) //第二次中断:下降沿中断,CCR
{
/* Get the 2nd Input Capture value */
uwIC1Value2_T3CH1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);
/* Capture computation */
if (uwIC1Value2_T3CH1 > uwIC1Value1_T3CH1) //获取高电平时间
{
uwHigh_T3CH1 = (uwIC1Value2_T3CH1 - uwIC1Value1_T3CH1);
}
else if (uwIC1Value2_T3CH1 < uwIC1Value1_T3CH1)
{
/* 0xFFFF is max TIM1_CCRx value */
uwHigh_T3CH1 = ((0xFFFF - uwIC1Value1_T3CH1) + uwIC1Value2_T3CH1) + 1;
}
uwIC1Value1_T3CH1 = uwIC1Value2_T3CH1; //赋值,保存高电平结束的时刻
uhCaptureIndex_T3CH1 = 2;
}
else if (uhCaptureIndex_T3CH1 == 2) //第三次中断:CCR
{
/* Get the 2nd Input Capture value */
uwIC1Value2_T3CH1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
/* Capture computation */
if (uwIC1Value2_T3CH1 > uwIC1Value1_T3CH1) //获取低电平时间
{
uwLow_T3CH1 = (uwIC1Value2_T3CH1 - uwIC1Value1_T3CH1);
}
else if (uwIC1Value2_T3CH1 < uwIC1Value1_T3CH1)
{
/* 0xFFFF is max TIM1_CCRx value */
uwLow_T3CH1 = ((0xFFFF - uwIC1Value1_T3CH1) + uwIC1Value2_T3CH1) + 1;
}
/* Frequency computation */
uwFrequency_T3CH1 = 1e6 / (uwHigh_T3CH1 + uwLow_T3CH1);
duty_T3CH1 = uwHigh_T3CH1 * 100.0f / (uwLow_T3CH1 + uwHigh_T3CH1); //单位是%
uhCaptureIndex_T3CH1 = 0;
}
}
//TIM3_CH2
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
if(uhCaptureIndex_T3CH2 == 0) //第一次中断:上升沿中断,CCR
{
/* Get the 1st Input Capture value */
uwIC2Value1_T3CH2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_FALLING);
uhCaptureIndex_T3CH2 = 1;
}
else if(uhCaptureIndex_T3CH2 == 1) //第二次中断:下降沿中断,CCR
{
/* Get the 2nd Input Capture value */
uwIC2Value2_T3CH2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_RISING);
/* Capture computation */
if (uwIC2Value2_T3CH2 > uwIC2Value1_T3CH2) //获取高电平时间
{
uwHigh_T3CH2 = (uwIC2Value2_T3CH2 - uwIC2Value1_T3CH2);
}
else if (uwIC2Value2_T3CH2 < uwIC2Value1_T3CH2)
{
/* 0xFFFF is max TIM1_CCRx value */
uwHigh_T3CH2 = ((0xFFFF - uwIC2Value1_T3CH2) + uwIC2Value2_T3CH2) + 1;
}
uwIC2Value1_T3CH2 = uwIC2Value2_T3CH2; //赋值,保存高电平结束的时刻
uhCaptureIndex_T3CH2 = 2;
}
else if (uhCaptureIndex_T3CH2 == 2) //第三次中断:CCR
{
/* Get the 2nd Input Capture value */
uwIC2Value2_T3CH2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
/* Capture computation */
if (uwIC2Value2_T3CH2 > uwIC2Value1_T3CH2) //获取低电平时间
{
uwLow_T3CH2 = (uwIC2Value2_T3CH2 - uwIC2Value1_T3CH2);
}
else if (uwIC2Value2_T3CH2 < uwIC2Value1_T3CH2)
{
/* 0xFFFF is max TIM1_CCRx value */
uwLow_T3CH2 = ((0xFFFF - uwIC2Value1_T3CH2) + uwIC2Value2_T3CH2) + 1;
}
/* Frequency computation */
uwFrequency_T3CH2 = 1e6 / (uwHigh_T3CH2 + uwLow_T3CH2);
duty_T3CH2 = uwHigh_T3CH2 * 100.0f / (uwLow_T3CH2 + uwHigh_T3CH2); //单位是%
uhCaptureIndex_T3CH2 = 0;
}
}
}
2、知识点概括
1)通过获取CCR寄存器的值,来得到高电平、低电平的时间,进而计算出频率和占空比;
2)状态切换时,记得修改上升、下降沿捕获;
3)回调函数中,要进行具体判断是哪一个定时器,在具体判断时哪一个通道;
4)原函数中的Error_Handler()用不到可以进行删除;