一、数码管
- SEG数码管显示(PA1、PA2、PA3),
PA1——SER串行输入数据,PA2——RCK输出锁存时钟,PA3——SCK移位寄存器时钟上升
- 初始化:GPIO模式(PA1、PA2、PA3):GPIO_Mode_Out_PP推挽输出
时钟:GPIOA
- 共阴极显示,即:高电平时,发光二极管点亮,(0:灭,1:亮)
- 每个数码管的8位二进制排序位【dp、g、f、e、d、c、b、a】
因为串行输入时,是从前往后输出,接受时,会将数据从后往前保存,即先接受dp位,将dp保存到最后面
因此,在设置输出到数码管的字段时,应该从后往前设置
关于串行输入是怎么操作的,不介绍,自行百度
因此,用数码管表示16进制的0~ F,使用如下数组,依次表示0~F以及全部熄灭uc8 Seg7[17] = { 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00};
使用代码如下:
(需记忆,是固定的)
void SEG_DisplayValue(u8 Bit1, u8 Bit2, u8 Bit3)//参数表示想让三个数码管显示的十六进制数
{
u8 i = 0; //做循环使用
u8 code_tmp = 0;//标识数码管点亮时对应的十六进制数
code_tmp = Seg7[Bit3];//设置第三个译码管
for(i=0;i<8;i++){
//注意,这里使用的是串行输入SER,即每次只输入一位数据,也就是把8位二进制的首位给输入到数码管当中,因此,需要连续输入8次
//这里的输入指从PC机写入的数据输入到开发板
if(code_tmp & 0x80 ){//0x80二进制为1000 0000,即每次循环将code_tmp的首位与1作逻辑与
//
GPIO_SetBits(GPIOA,GPIO_Pin_1);//SER_H;如果code_tmp首位为1,那么,串行输入的SER_H值置为1
}else{
GPIO_ResetBits(GPIOA,GPIO_Pin_1);//SER_L;//如果code_tmp首位为0,那么,串行输入的SER_H值置为0
}
GPIO_SetBits(GPIOA,GPIO_Pin_3);//SCK_H;//移位寄存器打开
code_tmp = code_tmp << 1; //让code_tmp 左移一位,准备判断下一位的串行输入的数据
//每次左移一位,即将下一位串行输出的数据放到首位
GPIO_ResetBits(GPIOA,GPIO_Pin_3);//SCK_L;//移位后,重新把移位寄存器关闭,防止出现错误
}
//其他数码管的操作同上
code_tmp = Seg7[Bit2];//设置第二个译码管
for(i=0;i<8;i++){
if(code_tmp & 0x80){
GPIO_SetBits(GPIOA,GPIO_Pin_1);//SER_H;
}else{
GPIO_ResetBits(GPIOA,GPIO_Pin_1);//SER_L;
}
GPIO_SetBits(GPIOA,GPIO_Pin_3);//SCK_H;
code_tmp = code_tmp << 1;
GPIO_ResetBits(GPIOA,GPIO_Pin_3);//SCK_L;
}
code_tmp = Seg7[Bit1];//设置第一个译码管
for(i=0;i<8;i++){
if(code_tmp & 0x80){
GPIO_SetBits(GPIOA,GPIO_Pin_1);//SER_H;
}else{
GPIO_ResetBits(GPIOA,GPIO_Pin_1);//SER_L;
}
GPIO_SetBits(GPIOA,GPIO_Pin_3);//SCK_H;
code_tmp = code_tmp << 1;
GPIO_ResetBits(GPIOA,GPIO_Pin_3);//SCK_L;
}
//负责输出数据的锁存,连续将输出时钟锁存打开、关闭,以保证数据不会受到其他程序段的影响
//当三个数码管的数据都已经输入完成,那么把数据锁存起来
GPIO_SetBits(GPIOA,GPIO_Pin_2);//RCLK_H;
GPIO_ResetBits(GPIOA,GPIO_Pin_2);//RCLK_L;
}
二、BUTTON(ADC)
- 需要盖帽PA5—AKEY上,此时,按扩展板上的8个按钮,会输出相应的ADC值,ADC同样是12位的
- 初始化:GPIO模式:GPIO_Mode_AIN(模拟输入)、
ADC(ADC1_IN5,查看芯片手册,可以发现,PA5对应的是ADC1的通道5)
NVIC:配置优先级
时钟:GPIOA、ADC1
- 其他函数调用
- RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADC时钟(只有这一个需要去"stm32f10x_rcc.h"里面找)
- ADC_Cmd(ADC1,ENABLE);//打开ADC
- ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE); //中断配置
-
- ADC_ResetCalibration(ADC1);//校准ADC
- ADC_StartCalibration(ADC1);//校准ADC
- while(ADC_GetCalibrationStatus(ADC1));//等待ADC校准完毕
-
- ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发
- ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_13Cycles5);//规则通道配置
- 判断按下的是哪一个键
- u8 Scan_Btn(void)
- {
- u16 btn_tmp = 0;
- //btn_tmp 通过中断方式读取ADC的值
- //S1~S8按键按下后会分别产生不同的电阻分压值,通过ADC显示,其电压值大致分为14份,按下不同的键,会产生不同的电压值,每次读取到的值不一定完全相同,但一定在对应的区间当中
- if(btn_tmp < 0x0FFF/14){
- return 1;//按下按键S1
- }else if((btn_tmp > 0x0FFF/14) && (btn_tmp < 0x0FFF/14*3)){
- return 2;//按下按键S2
- }else if((btn_tmp > 0x0FFF/14*3) && (btn_tmp < 0x0FFF/14*5)){
- return 3;//按下按键S3
- }else if((btn_tmp > 0x0FFF/14*5) && (btn_tmp < 0x0FFF/14*7)){
- return 4;//按下按键S4
- }else if((btn_tmp > 0x0FFF/14*7) && (btn_tmp < 0x0FFF/14*9)){
- return 5;//按下按键S5
- }else if((btn_tmp > 0x0FFF/14*9) && (btn_tmp < 0x0FFF/14*11)){
- return 6;//按下按键S6
- }else if((btn_tmp > 0x0FFF/14*11) && (btn_tmp < 0x0FFF/14*13)){
- return 7;//按下按键S7
- }else if((btn_tmp > 0x0FFF/14*13) && (btn_tmp < 0x0FDF)){
- return 8;//按下按键S8
- }
- else{
- return 0; //error status & no key
- }
- }
三、温度传感器(DS18B20)
- 盖帽接PA6—TDQ
- 直接使用官方提供的ds18b20.c和ds18b20.h的初始化函数ds18b20_init_x();
并自己写一个函数,用来读取温度的值
- 读取温度值
- s16 ds18b20_read(void)//返回值为16位数据
- {
- u8 val1,val2;
- s16 x = 0;
- ow_reset();
- ow_byte_wr(OW_SKIP_ROM);
- ow_byte_wr(DS18B20_CONVERT);
- delay_us(750000);
- ow_reset();
- ow_byte_wr( OW_SKIP_ROM );
- ow_byte_wr ( DS18B20_READ );
- val1 = ow_byte_rd();//先读取低8位的温度值
- val2 = ow_byte_rd();//再读取高8位的温度值
- x = (val2<<8)+val1;//整合成16位的温度值
- return x;
- }
四.温湿度传感器(DHT11)
- 盖帽接PA7—HDQ
- 直接使用官方提供的dht11.c和dht11.h的初始化函数dht11_init();
- 直接使用温湿度读取函数dht11_read();
unsigned int dht11_read(void);
//返回一个32位的数据,数据格式为:
//8位湿度整数+8位湿度小数+8位温度整数+8位温度小数
int DHT=dht11_read();
DHT>>24;//湿度的整数部分
(DHT>>8)&0xff//温度的整数部分
//因此在显示湿度时,应该右移24位,温度应该右移8位,同时忽略前16位
五、MEMS传感器(LIS302DL)
- 盖帽需要连接PA4—SCL、PA5—SDA
- MEMS传感器其实和EEPROM类似,都是使用I²C,只不过EEPROM使用引脚PB7、PB6,而MEMS传感器使用引脚PA5、PA4
- 同样的,直接使用官方提供的i2c.c、i2c.h文档,但要把
- #define I2C_PORT GPIOB
- #define SDA_Pin GPIO_Pin_7
- #define SCL_Pin GPIO_Pin_6
- 改为
- #define I2C_PORT GPIOA
- #define SDA_Pin GPIO_Pin_5
- #define SCL_Pin GPIO_Pin_4
- 如果要同时使用EEPROM,则把这俩个文档名字改一下即可
- 写入LIS302DL、读取LIS302DL的函数
- uint8_t LIS302DL_Read(uint8_t adds)
- {
- uint8_t data;
- I2CStart();
- I2CSendByte(0x38);
- I2CWaitAck();
- I2CSendByte(adds);
- I2CWaitAck();
- I2CStart();
- I2CSendByte(0x39);
- I2CWaitAck();
- data=I2CReceiveByte();
- I2CWaitAck();
- I2CStop();
- return data;
- }
- void LIS302DL_Write(uint8_t adds,uint8_t data)
- {
- I2CStart();
- I2CSendByte(0x38);
- I2CWaitAck();
- I2CSendByte(adds);
- I2CWaitAck();
- I2CSendByte(data);
- I2CWaitAck();
- I2CStop();
- }
- //可以发现,LIS302DL的接受和发送函数和EEPROM的完全相同,区别只是器件的读写地址发生了变化。
- //将0xa0、0xa1的读写EEPROM地址改为0x38、0x39的读写LIS302DL地址
六、光敏电阻(DO)
- DO数字量输出接口(0和1)
- 盖帽PA3—TRDO
- 初始化:配置GPIO:PA3——GPIO_Mode_IPU(上拉输入)
时钟:GPIOA
- 模块在无光环境以及环境光线亮度达不到设定阈值时,DO端输出高电平,当外界环境光线亮度超过设定阈值时,DO端输出低电平;
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3) == Bit_RESET){//GPIO_ReadInputDataBit:读取引脚输入电平
LCD_DisplayStringLine(Line7, (u8*)" DO:High ");//低电平表示亮度达到阙值
}else{
LCD_DisplayStringLine(Line7, (u8*)" DO:Low ");
七、光敏电阻(AO)
- DO模拟电压输出接口
- 盖帽PA4—TRAO
- 初始化:配置GPIO:PA4——GPIO_Mode_AIN(模拟输入)
ADC(ADC1_IN4,查看芯片手册,可以发现,PA4对应的是ADC1的通道4)
时钟:GPIOA、ADC1
若使用中断获取光敏电阻的值,那么配置NVIC:ADC_IT_EOC
- 其他函数调用
- RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADC时钟(只有这一个需要去"stm32f10x_rcc.h"里面找)
- ADC_Cmd(ADC1,ENABLE);//打开ADC
- ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE); //中断配置
-
- ADC_ResetCalibration(ADC1);//校准ADC
- ADC_StartCalibration(ADC1);//校准ADC
- while(ADC_GetCalibrationStatus(ADC1));//等待ADC校准完毕
-
- ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发
- ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_13Cycles5);//规则通道配置
- 光敏电阻根据外界光强不同,会产生不同的电阻值,光照愈强,阻值就愈低。随着光照强度的升高,电阻值迅速降低,可降低至1KΩ以下。随着电阻下降,电压不断升高。ADC读取光敏电阻两侧的电压值,来量化光强度值
公式:tmp/(4096.-tmp)*10),其中tmp为ADC读取得到的值
八、AD采集x2
- 盖帽PA4—AO1,PA5—AO2
- 俩个ADC对应电位器RP5、RP6
- 初始化:GPIO模式:PA4、PA5 :GPIO_Mode_AIN(模拟输入)、
ADC(ADC1_IN4、ADC1_IN5,查看芯片手册,可以发现,PA4对应的是ADC1的通道4;PA5对应的是ADC1的通道5)
时钟:GPIOA、ADC1
- ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;//因为是同时使用俩个ADC,不能在配置为独立模式;
- ADC_InitStructure.ADC_NbrOfChannel = 2;//使用规则通道的数量为2个
- //RegSimult:同步规则模式
- NVIC:配置优先级
时钟:GPIOA、ADC1
- 其他函数调用
- RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADC时钟(只有这一个需要去"stm32f10x_rcc.h"里面找)
- ADC_Cmd(ADC1,ENABLE);//打开ADC
- ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE); //中断配置
-
- ADC_ResetCalibration(ADC1);//校准ADC
- ADC_StartCalibration(ADC1);//校准ADC
- while(ADC_GetCalibrationStatus(ADC1));//等待ADC校准完毕
-
- ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发
- ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_239Cycles5);
- ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_239Cycles5);//规则通道配置
- 读取ADC值
u16 Get_ADCs(u8 channel)//可以使用中断方式
{
//因为ADC1同时使用俩个通道读取,因此,每次读取ADC的值,都要选择要读取的通道
u16 ADC_Val = 0;
ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_239Cycles5); //这一句是重点
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
ADC_Val = ADC_GetConversionValue(ADC1);
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
ADC_SoftwareStartConvCmd(ADC1, DISABLE);
return ADC_Val;
}
九、9.脉冲测量(PWM)
- 盖帽PA6—PWM1—电位器PR1—TIM3_CH1 ,PA7—PWM2—电位器PR2—TIM3_CH2
- 在这里插入代码片
- 初始化:GPIO模式:PA4、PA5 :GPIO_Mode_IN_FLOATING(浮空输入)、
TIM:配置结构体TIM_ICInitTypeDef,测量的是开发板上输入PWM,因此配置的是TIM输入结构体
时钟:GPIOA、TIM3
NVIC
其他函数调用
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI2FP2);//选择输入触发源:TI2:表示通道2,PF2:经过滤波器后将接到捕捉比较通道IC2;
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//选择从模式 上升沿重新初始化计数器,并且产生一个更新寄存器的信号
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);//配置从模式
TIM_Cmd(TIM3, ENABLE);
TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);
中断函数
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_CC2) == SET){
TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
IC2Value = TIM_GetCapture2(TIM3);
if (IC2Value != 0){
DutyCycle = (TIM_GetCapture1(TIM3) * 100) / IC2Value;//占空比,
Frequency = SystemCoreClock / IC2Value;//频率,单位:HZ
}else{
DutyCycle = 0;
Frequency = 0;
}
}
}