做一个静态网站导航要多少钱,网站报价,photoshop网站模板设计教程,乌兰浩特网站制作目录 1、环境搭建
2、按键控制灯电机
LED
电机
垂直按键(机械按键)
3、串口调试功能
4、定时器延时和定时器中断
5、振动强弱调节
6、万年历
7、五方向按键
1、原理及分析
2、程序设计 1、环境搭建
需求:
搭建一个STM32F411CEU6工程
分析:
C / C 宏定义栏…目录 1、环境搭建
2、按键控制灯电机
LED
电机
垂直按键(机械按键)
3、串口调试功能
4、定时器延时和定时器中断
5、振动强弱调节
6、万年历
7、五方向按键
1、原理及分析
2、程序设计 1、环境搭建
需求:
搭建一个STM32F411CEU6工程
分析:
C / C 宏定义栏: STM32F411xE
在哪里找? STM32F411xE 2、按键控制灯电机
需求:
按键控制灯和电机的开关
第一次按键LED_ON
第二次按键LED_OFF
第三次按键MI_ON
第四次按键MI_OFF LED
创建.c和.h文件
添加文件到工程
看原理图 LED所用到的IO口 低电平点亮 高电平熄灭 输出模式
程序设计 LED初始化函数
/***********************************************
*函数名 :led_init
*函数功能 :对LED灯所用IO口初始化配置
*函数参数 :无
*函数返回值:无
*函数描述 :LED------PA7
************************************************/
void led_init(void)
{RCC-AHB1ENR | (10);GPIOA-MODER ~(314);GPIOA-MODER | (114);GPIOA-OTYPER ~(17);GPIOA-OSPEEDR ~(314);GPIOA-PUPDR ~(314);//初始状态 关GPIOA-ODR | (17);
} 开关灯的宏定义
#ifndef _LED_H
#define _LED_H
#include stm32f4xx.h // Device header#define LED_OFF (GPIOA-ODR | (17))
#define LED_ON (GPIOA-ODR ~(17))
#define LED_OVERTURN (GPIOA-ODR ^ (17))void led_init(void);#endif 电机
创建.c和.h文件
添加文件到工程
看原理图 电机所用到的IO口 高电平转动 低电平停止 输出模式
程序设计 电机初始化函数 /***********************************************
*函数名 :motor_init
*函数功能 :对电机所用IO口初始化配置
*函数参数 :无
*函数返回值:无
*函数描述 :motor------PB10
************************************************/
void motor_init(void)
{RCC-AHB1ENR | (11);GPIOB-MODER ~(320);GPIOB-MODER | (120);GPIOB-OTYPER ~(110);GPIOB-OSPEEDR ~(320);GPIOB-PUPDR ~(320);//初始状态 关GPIOB-ODR ~(110);
}电机转动和停止的宏定义
#ifndef _MOTOR_H
#define _MOTOR_H#include stm32f4xx.h // Device header#define MI_OFF (GPIOB-ODR ~(110))
#define MI_ON (GPIOB-ODR | (110))
#define MI_OVERTURN (GPIOB-ODR ^ (110))void motor_init(void);
#endif 垂直按键(机械按键)
创建.c和.h文件
添加文件到工程
看原理图 按键所用到的IO口 高电平按下 低电平抬起 输入模式
程序设计 按键初始化函数
static void delay_ms(u32 ms)
{u32 i 100 / 4 * 1000 * ms;while(i){i--;}
}/***********************************************
*函数名 :key_init
*函数功能 :对KEY所用IO口初始化配置
*函数参数 :无
*函数返回值:无
*函数描述 :KEY_OK------PA0
************************************************/
void key_init(void)
{RCC-AHB1ENR | (10);GPIOA-MODER ~(30);GPIOA-PUPDR ~(30);
}按键扫描函数
/***********************************************
*函数名 :key_scan
*函数功能 :按键扫描函数
*函数参数 :无
*函数返回值:u8
*函数描述 :
************************************************/
u8 key_scan(void)
{u8 key 0xff;static u8 key_flag 1;//判断按键按下if(KEY key_flag){delay_ms(15);if(KEY){key KEY_OK;key_flag 0;MOTOR_VAL 1000;timer_buff[3]0; }}//判断按键抬起if(!KEY){key_flag 1;}return key;
}3、串口调试功能
程序设计 串口初始化配置
/***********************************************
*函数名 :usart1_init
*函数功能 :串口1初始化配置
*函数参数 :u32 bps
*函数返回值:无
*函数描述 :USART1_Tx ---------PA9 USART1_Rx ---------PA10
************************************************/
void usart1_init(u32 bps)
{/*IO口控制器配置*///端口时钟使能RCC-AHB1ENR | (10);//端口模式配置GPIOA-MODER ~((318) | (320));GPIOA-MODER | ((218) | (220));//端口输出类型GPIOA-OTYPER ~(19);//端口输出速度GPIOA-OSPEEDR ~(318); //2M//上下拉配置GPIOA-PUPDR ~((318) | (320));//复用功能配置GPIOA-AFR[1] ~(154);GPIOA-AFR[1] | (74); //PA9配置串口1的发送复用功能GPIOA-AFR[1] ~(158);GPIOA-AFR[1] | (78); //PA10配置串口1的接收复用功能/*串口1控制器配置*///串口时钟使能RCC-APB2ENR | (14);//CR1USART1-CR1 ~(115); //16倍过采样USART1-CR1 ~(112); //8位字长USART1-CR1 | (13) ; //发送使能USART1-CR1 | (12) ; //接收使能//CR2USART1-CR2 ~(312); //1个停止位//BRRUSART1-BRR 100000000/bps;/*NVIC控制器配置*///优先级分组-----------------------------主函数其他初始化上面//计算优先级编码值u32 pri NVIC_EncodePriority (5,1,2);//设确定具体中断源NVIC_SetPriority(USART1_IRQn, pri);//使能NVIC响应通道NVIC_EnableIRQ(USART1_IRQn);//串口1空闲中断使能USART1-CR1 | (14);//串口1接收中断使能USART1-CR1 | (15);//串口使能USART1-CR1 | (113);} 发送一个字节函数
/***********************************************
*函数名 :usart1_send_byte
*函数功能 :串口1发送一个字节函数
*函数参数 :u8 data
*函数返回值:无
*函数描述 :
************************************************/
void usart1_send_byte(u8 data)
{//等待之前的发送完成(等待转态寄存器的发送完成位置1)while(!(USART1-SR (16)));// //把要发送的数据赋值给数据寄存器USART1-DR data;}发送一个字符串函数
/***********************************************
*函数名 :usart1_send_str
*函数功能 :串口1发送一个字符串函数
*函数参数 :u8 *str
*函数返回值:无
*函数描述 :
************************************************/
void usart1_send_str(u8 *str)
{while(*str ! \0){//发送字符usart1_send_byte(*str);//下一字符的地址str;}} 中断服务函数
/***********************************************
*函数名 :USART1_IRQHandler
*函数功能 :串口1中断服务函数
*函数参数 :无
*函数返回值:无
*函数描述 :
************************************************/
u8 usart1_buff[10];void USART1_IRQHandler(void)
{u8 data;//判断是接收中断信号触发if(USART1-SR (15)){//清除中断标志位//紧急事件}//判断是空闲中断信号触发if(USART1-SR (14)){//清除中断标志位USART1-SR;USART1-DR;//紧急事件}} 4、定时器延时和定时器中断
定时器延时用timer11
定时器11没有单次计数配置只能是循环计数
等待计数完成后要关闭定时器。
定时器中断用timer9 注意
时钟频率
分频
不同的芯片可能没有基本定时器6和7 程序设计
定时器11毫秒延时函数
/***********************************************
*函数名 :tim11_delay_ms
*函数功能 :定时器11延时
*函数参数 :u16 ms
*函数返回值:无
*函数描述 :100MHZ--------------100000/ms10000分频-----------10/ms
************************************************/
void tim11_delay_ms(u16 ms)
{//定时器时钟使能RCC-APB2ENR | (118);//CR1TIM11-CR1 | (17); //使能影子寄存器//TIM11-CR1 | (13); //单次计数模式TIM11-CR1 ~(11); //产生更新事件//PSC分频寄存器TIM11-PSC 10000-1; //10000分频//ARR重载寄存器TIM11-ARR 10 * ms - 1;//人为产生更新事件UGTIM11-EGR | (10);//清除状态寄存器更新完成位TIM11-SR ~(10);//使能计数器TIM11-CR1 | (10);//等待计数完成while(!(TIM11-SR (10)));//关闭定时器TIM11-CR1 ~(10);}
定时器11微秒延时函数
/***********************************************
*函数名 :TIM11_delay_us
*函数功能 :定时器11延时微秒
*函数参数 :u16 us
*函数返回值:无
*函数描述 :100MHZ--------------100/us50分频-----------2/us
************************************************/
void TIM11_delay_us(u16 us)
{//定时器时钟使能RCC-APB2ENR | (118);//CR1TIM11-CR1 | (17); //使能影子寄存器//TIM11-CR1 | (13); //单次计数模式TIM11-CR1 ~(11); //产生更新事件//PSC分频寄存器TIM11-PSC 50-1; //50分频//ARR重载寄存器TIM11-ARR 2 * us - 1;//人为产生更新事件UGTIM11-EGR | (10);//清除状态寄存器更新完成位TIM11-SR ~(10);//使能计数器TIM11-CR1 | (10);//等待计数完成while(!(TIM11-SR (10)));//关闭定时器TIM11-CR1 ~(10);
}
定时器9毫秒级定时中断函数
/***********************************************
*函数名 :tim9_interrupt_ms
*函数功能 :定时器9毫秒级定时中断
*函数参数 :u16 ms
*函数返回值:无
*函数描述 :100MHZ--------------100000/ms10000分频-----------10/ms
************************************************/
void tim9_interrupt_ms(u16 ms)
{/*定时器控制器配置*///定时器时钟使能RCC-APB2ENR | (116);//CR1TIM9-CR1 | (17); //使能影子寄存器TIM9-CR1 ~(13); //循环计数模式TIM9-CR1 ~(12); TIM9-CR1 ~(11); //PSC 分频TIM9-PSC 10000-1;//ARRTIM9-ARR 10 * ms - 1;//EGR UG位人为产生更新事件 状态寄存器的0号位置1;TIM9-EGR | (10);//清零状态寄存器TIM9-SR ~(10); /*NVIC控制器配置*/ //优先级分组//计算优先级编码值u32 pri NVIC_EncodePriority (5,1,1);//设确定具体中断源NVIC_SetPriority(TIM1_BRK_TIM9_IRQn, pri);//使能NVIC响应通道NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn);//DIER 定时中断使能TIM9-DIER | (10);//定时器使能TIM9-CR1 | (10);
}
5、振动强弱调节
电机变速用PWM
通过查复用表可知 电机-----PB10--------TIM2_CH3 程序设计
定时器2通道3输出PWM驱动电机函数
/***********************************************
*函数名 :tim2_ch3_pwm_motor
*函数功能 :定时器2通道3驱动PB10,输出PWM
*函数参数 :无
*函数返回值:无
*函数描述 :100MHZ--------------100000/ms-----100/us100分频-----------1/us周期定位1ms PB10
************************************************/
void tim2_ch3_pwm_motor(void)
{/*IO控制器配置*///端口时钟使能RCC-AHB1ENR | (11);//端口模式配置-------复用模式GPIOB-MODER ~(320);GPIOB-MODER | (220);//输出类型GPIOB-OTYPER ~(110);//输出速度GPIOB-OSPEEDR ~(320);//上下拉GPIOB-PUPDR ~(320);//复用功能寄存器GPIOB-AFR[1] ~(158);GPIOB-AFR[1] | (18);/*通用定时器控制器配置*///定时器时钟使能RCC-APB1ENR | (10);//CR1TIM2-CR1 | (17); //重载的影子寄存器TIM2-CR1 ~(35); //边沿对齐计数模式TIM2-CR1 ~(14); //递增计数TIM2-CR1 ~(13); //连续模式TIM2-CR1 ~(12);TIM2-CR1 ~(11);//SMCRTIM2-SMCR ~(70); //选择内部时钟//CCMRxTIM2-CCMR2 ~(30); //把通道3定位输出通道TIM2-CCMR2 | (13); //比较寄存器影子TIM2-CCMR2 ~(74);TIM2-CCMR2 | (64); //PWM1//CCERTIM2-CCER ~(19); //高电平为有效电平//PSCTIM2-PSC 100-1;//ARRTIM2-ARR 1000-1;//CCRxTIM2-CCR3 0;//EGRTIM2-EGR | (10); //人为产生更新事件//通道3打开TIM2-CCER | (18);//定时器使能TIM2-CR1 | (10);
}
6、万年历
时钟源 外部低速时钟 32.768KHZ 内部低速时钟 32KHZ
程序设计
RTC初始化配置
/***********************************************
*函数名 :RTC_init
*函数功能 :RTC初始化配置
*函数参数 :无
*函数返回值:无
*函数描述 :
************************************************/
void RTC_init(RTC_t time)
{/*解除RTC和相关寄存器保护*///使能电源控制器时钟RCC-APB1ENR | (128);//PWR-CR 的DBP位写1解除RTC控制器保护 PWR-CR | (18);//秘钥寄存器写入值,解除RTC相关寄存器保护RTC-WPR 0xca;RTC-WPR 0x53;/*RTC时钟源设置*///使能内部低速震荡器RCC-CSR | (10);//等待内部部振荡器就绪while(!(RCC-CSR (11)));//选择内部低速时钟源RCC-BDCR | (28);//使能RTC时钟RCC-BDCR | (115);/*RTC相关寄存器*///CRRTC-CR ~(16); //24hRTC-CR ~(15); //开影子寄存器RTC-WPR 0xff;/*设置初始时间*/if(RTC-BKP0R ! 500){RTC-BKP0R 500;set_time(time);}}设置时间函数
/***********************************************
*函数名 :in_dec_out_bcd
*函数功能 :将十进制数据转换成BCD码形式
*函数参数 :u8 dec
*函数返回值:u8
*函数描述 :设置时间时候使用
************************************************/
u8 in_dec_out_bcd(u8 dec)
{return ((dec / 10) 4) | (dec % 10);
}/***********************************************
*函数名 :set_time
*函数功能 :设置时间函数
*函数参数 :RTC_t time
*函数返回值:无
*函数描述 :
************************************************/
void set_time(RTC_t time)
{u32 temp_t 0;u32 temp_d 0;//解除寄存器保护RTC-WPR 0xca;RTC-WPR 0x53;//让日历进入初始化模式RTC-ISR | (17);//等待可以更新日历值while(!(RTC-ISR (16)));//将设置的十进制数据转换成BCD码temp_t (in_dec_out_bcd(time.h))16 |(in_dec_out_bcd(time.m))8 |in_dec_out_bcd(time.s);temp_d (in_dec_out_bcd(time.year-2000))16 |(in_dec_out_bcd(time.week))13 |(in_dec_out_bcd(time.mon))8 |(in_dec_out_bcd(time.day));//设置TR 和 DRRTC-TR temp_t;RTC-DR temp_d;//退出初始化模式RTC-ISR ~(17);//激活写保护RTC-WPR 0xff;}
获取时间函数
/***********************************************
*函数名 :in_bcd_out_dec
*函数功能 :将BCD码形式数据转换成十进制
*函数参数 :u8 bcd
*函数返回值:u8
*函数描述 :获取时间使用
************************************************/
u8 in_bcd_out_dec(u8 bcd)
{return (bcd 4) * 10 (bcd 0x0f);
}/***********************************************
*函数名 :get_time
*函数功能 :获取时间函数
*函数参数 :无
*函数返回值:RTC_t
*函数描述 :
************************************************/
RTC_t get_time(void)
{RTC_t t;u32 temp_t 0;u32 temp_d 0;//解除寄存器保护RTC-WPR 0xca;RTC-WPR 0x53;//ISR寄存器中RSF位0RTC-ISR ~(15);//等待同步完成(等待ISR寄存器中RSF位自动变为1)while(!(RTC-ISR (15)));//读出时间寄存器的值(BCD码)temp_t RTC-TR;//ISR寄存器中RSF位0RTC-ISR ~(15);//等待同步完成(等待ISR寄存器中RSF位自动变为1)while(!(RTC-ISR (15)));//读出日期寄存器的值(BCD码)temp_d RTC-DR;//将读出的BCD码转换成十进制形式t.year in_bcd_out_dec((temp_d 0xff0000) 16) 2000;t.week in_bcd_out_dec((temp_d 0xe000) 13);t.mon in_bcd_out_dec((temp_d 0x1f00) 8);t.day in_bcd_out_dec((temp_d 0x3f) 0);t.h in_bcd_out_dec(temp_t 16);t.m in_bcd_out_dec(temp_t 8);t.s in_bcd_out_dec(temp_t 0);//激活写保护RTC-WPR 0xff;//返回结构体变量return t;
} 7、五方向按键
1、原理及分析
需求:
五方向的按键扫描函数 分析:
垂直按键不参与ADC控制
其他四方向的原理通过ADC转换得到不同的份数每份份数代表着不同的方向 通过原理图用到的是PA3
通过查表知道用到ADC1的通道3 四个按键方向接在ADC1的3号通道上,不同的方向接了不同的电阻,不同的按键方向就会体现不同的电压值,不同电压值通过AD转换,就会体现出不同的份数.不同的份数就可以识别不同方向的按键. 2、程序设计
设计ADC相关程序
ADC的配置方式有两种中断的方式获取数据、查询等待的方式获取数据
查询等待的方式
ADC初始化配置函数
/***********************************************
*函数名 :adc1_ch3_Init
*函数功能 :ADC1通道3
*函数参数 :无
*函数返回值:无
*函数描述 :PA3-----ADC1_CH3------四方向按键
************************************************/
void adc1_ch3_Init(void)
{/*IO口控制器配置*///端口时钟使能RCC-AHB1ENR | (10);GPIOA-MODER ~(36);GPIOA-MODER | (36); //模拟模式/*ADC控制器配置*///ADC控制器时钟使能RCC-APB2ENR | (18);//CR1ADC1-CR1 ~(324); //精度12位ADC1-CR1 | (18); //扫描模式//CR2ADC1-CR2 ~(111); //右对齐ADC1-CR2 | (110); //每个转换完成标志位就置1ADC1-CR2 ~(11); //单次//SMPRADC1-SMPR2 | (79); //通道3,480个周期//SQR1ADC1-SQR1 ~(0xf20); //一共有一个转换 //SQR3ADC1-SQR3 ~(0x1f0);ADC1-SQR3 | (30); //第一个转换是3号通道//CCRADC-CCR ~(316);ADC-CCR | (116); //4分频//ADC使能ADC1-CR2 | (10);
} 获取转换数据函数 /***********************************************
*函数名 :get_adc1_data
*函数功能 :获取adc1的转换数据
*函数参数 :无
*函数返回值:u16
*函数描述 :PA3-----ADC1_CH3------四方向按键
************************************************/
u16 get_adc1_data(void)
{u16 data;//开始转换ADC1-CR2 | (130);//等待转换完成 while(!(ADC1-SR (11)));//获取转换数据到变量data ADC1-DR;//返回转换值return data;
}通过调用ADC的获取函数再通过测试按键得到不同方向的份数值 KEY_UP 1000~1100 KEY_Down 1300~1400 KEY_L 4000 KEY_R 2000~2100 设计四方向按键相关程序 四方向按键扫描函数
/***********************************************
*函数名 :fun_key_init
*函数功能 :五方向按键初始化
*函数参数 :无
*函数返回值:无
*函数描述 :
************************************************/
void fun_key_init(void)
{key_init();adc1_ch3_Init();
}/***********************************************
*函数名 :fun_key_scan
*函数功能 :五方向按键扫描函数
*函数参数 :无
*函数返回值:u8
*函数描述 :
************************************************/
u8 fun_key_scan(void)
{u16 data;u8 key_data 0xff;static u8 adc_flag 1;//四方向按键data get_adc1_data();if(adc_flag data 1000 data 1100 ) //UP{adc_flag 0;key_data KEY_UP;}else if(adc_flag data 1300 data 1400) //Down{adc_flag 0;key_data KEY_Down;}else if(adc_flag data 4000) //left{adc_flag 0;key_data KEY_Left;}else if(adc_flag data 2000 data 2100) //right{adc_flag 0;key_data KEY_Right;}if(data 20){//解锁标志位adc_flag 1;}return key_data;
}结合垂直按键写出五方向按键扫描函数
/***********************************************
*函数名 :fun_key_scan
*函数功能 :五方向按键扫描函数
*函数参数 :无
*函数返回值:u8
*函数描述 :
************************************************/
u8 fun_key_scan(void)
{u16 data;u8 key_data 0xff;static u8 adc_flag 1;//垂直按键key_data key_scan();//四方向按键data get_adc1_data();if(adc_flag data 1000 data 1100 ) //UP{adc_flag 0;key_data KEY_UP;}else if(adc_flag data 1300 data 1400) //Down{adc_flag 0;key_data KEY_Down;}else if(adc_flag data 4000) //left{adc_flag 0;key_data KEY_Left;}else if(adc_flag data 2000 data 2100) //right{adc_flag 0;key_data KEY_Right;}if(data 20){//解锁标志位adc_flag 1;}return key_data;
}若想要实现按住不抬起能每隔一秒返回一次键值
利用定时中断,超时检测1S解锁一次标志位
u8 fun_key_scan(void)
{u16 data;u8 key_data 0xff;static u8 adc_flag 1;//垂直按键key_data key_scan();//四方向按键data get_adc1_data();if(adc_flag data 1000 data 1100 ) //UP{adc_flag 0;key_data KEY_UP;timer_buff[3]0; //开始1s计时MOTOR_VAL 1000;}else if(adc_flag data 1300 data 1400) //Down{adc_flag 0;key_data KEY_Down;timer_buff[3]0; //开始1s计时MOTOR_VAL 1000;}else if(adc_flag data 4000) //left{adc_flag 0;key_data KEY_Left;timer_buff[3]0; //开始1s计时MOTOR_VAL 1000;}else if(adc_flag data 2000 data 2100) //right{adc_flag 0;key_data KEY_Right;timer_buff[3]0; //开始1s计时MOTOR_VAL 1000;}if(data 20 || timer_buff[3]1000){//解锁标志位adc_flag 1;}return key_data;
}