[STM32F4] 【STM32F469I试用】+基于标准库的Keil工程_带延时LED按键串口

[复制链接]
 楼主| 湛只为无双 发表于 2015-12-12 17:25 | 显示全部楼层 |阅读模式
本帖最后由 湛只为无双 于 2016-1-19 21:37 编辑

还有六个帖子点击查看哟~~
https://bbs.21ic.com/icview-1237978-1-5.html
https://bbs.21ic.com/icview-1238504-1-5.html
https://bbs.21ic.com/icview-1247976-1-1.html
https://bbs.21ic.com/icview-1266650-1-1.html
https://bbs.21ic.com/icview-1270560-1-1.html
https://bbs.21ic.com/icview-1277894-1-1.html
在拿到板子后后立马开始建基于Keil的标准库,在开发过程中可以选择标准库也可以选择由CubeMX生成的基于Cube库工程,由于在学STM32之初就是使用的标准库,并且很多以前写的程序也是基于标准库的,查阅相关资料后就决定使用标准库进行开发。在使用标准库之前建议下载最新版的F4标准库,然后进行一步步的工程建立,这里给大家提供相关的下载网址,供大家参考。
http://www.stmcu.org/document/download/index/id-211720
http://www.stmcu.org/document/download/index/id-211721
http://www.stmcu.org/document/download/index/id-211722
http://www.stmcu.org/document/download/index/id-211723
最新版的标准库版本为1.6.1,里面提供了标准外设库。

一、外部晶振8M在标准库中的修改在使用标准外设库的过程中需要注意的是,STM32F469DISCOVERY的外部晶振时钟为8MHz,而不是标准库中通用的25MHz,这点在原理图中可以看出来。
1.png

那么如果使用8MHz晶振需要修改哪些地方呢?在这里给大家提供修改的思路:
①修改stm32f4xx.h中的134行将 HSE_VALUE设为8000000,这个意识是告诉固件库外部晶振的数值为8000000,而不是原来的25000000
  1. #if !defined  (HSE_VALUE)
  2.   #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
  3. #endif /* HSE_VALUE */
复制代码
②在修改完stm32f4xx.h以后,还需要修改进入时钟前分频器的大小,原始的25M时钟进入芯片内部第一步是25分频为1M,那么这样我就不用过多解释,如果外部时钟为8M,并且分频为1M,只需要修改分频值大小即可,设置时钟在system_stm32f4xx.c里面的第371行,将PLL_M,由原来的25更改为8即可。
  1. #if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F469_479xx)
  2. /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
  3. #define PLL_M      8
复制代码
经过以上的步骤,就可以实现外部8M的晶振时钟了。

二、LED程序的编写
根据DISCOVERY的官方原理图可以知道,外部的LED一共有4个,分别对应了PG6 PD4 PD5 PK3
原理图如下:
2.png
根据原理图可以知道,当stm32对应端口输出高电平时,LED熄灭;当对应端口输出低电平时,LED点亮。属于使用灌电流的方式驱动LED的亮灭。
那么就根据此来进行LED程序的初始化:
Cortex-M4内核支持位段操作,在控制LED亮灭的过程中使用了位段操作,首先定位LED的位段:
  1. #define        LED1        PGout(6)
  2. #define        LED2        PDout(4)
  3. #define        LED3        PDout(5)
  4. #define        LED4        PKout(3)
复制代码
然后进行LED的初始化,设置为普通的推挽输出模式:
  1. void LED_Init(void)
  2. {
  3.         GPIO_InitTypeDef GPIO_Initstructure;
  4.         
  5.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOK,ENABLE);
  6.         
  7.         GPIO_Initstructure.GPIO_Pin=GPIO_Pin_6;
  8.         GPIO_Initstructure.GPIO_OType=GPIO_OType_PP;
  9.         GPIO_Initstructure.GPIO_PuPd=GPIO_PuPd_UP;
  10.         GPIO_Initstructure.GPIO_Mode=GPIO_Mode_OUT;
  11.         GPIO_Initstructure.GPIO_Speed=GPIO_High_Speed;
  12.         GPIO_Init(GPIOG,&GPIO_Initstructure);
  13.         LED1=1;
  14.         
  15.         GPIO_Initstructure.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5;
  16.         GPIO_Init(GPIOD,&GPIO_Initstructure);
  17.         LED2=1;LED3=1;
  18.         
  19.         GPIO_Initstructure.GPIO_Pin=GPIO_Pin_3;
  20.         GPIO_Init(GPIOK,&GPIO_Initstructure);
  21.         LED4=1;
  22. }
复制代码
这样就完成了LED的初始化,如果要进行LED的亮灭操作,只需要对LED1、LED2、LED3、LED4赋值即可。

三、按键程序的编写按键的程序和LED程序大同小异,只是将IO口方向设置为输入模式即可,根据原理图可以看出:
3.png

按键所使用的输入为PA0,那么直接设置PA0为输入,同样使用位段操作来定义按键的输入:
  1. #define KEY1 PAin(0)
复制代码
  1. void KEY_Init(void)
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;
  4.         
  5.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  6.         
  7.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  8.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  9.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  10.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  11. }
复制代码
通过查询KEY1的值,即可获得当前按键的状态。

四、串口程序的编写
串口使用的端口为PB10和PB11,对应芯片的USART3,连接到了ST-LINK/V2-1的虚拟串口上,那么可以通过设置USART3进行串口数据发送。 4.png

通过以下代码可以完成对串口3的初始化:
  1. void USART3_Init(u32 BandRate)
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;
  4.         USART_InitTypeDef USART_InitStructure;

  5. #if USART3_RX_EN
  6.         NVIC_InitTypeDef NVIC_InitStructure;
  7. #endif

  8.         //PB10:USART3_TX; PB11:USART3_RX
  9.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  10.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

  11.         GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);  
  12.         GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);

  13.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
  14.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  15.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  16.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  17.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  18.         GPIO_Init(GPIOB, &GPIO_InitStructure);

  19.         USART_InitStructure.USART_BaudRate = BandRate;//波特率设置
  20.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  21.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  22.         USART_InitStructure.USART_Parity = USART_Parity_No;
  23.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  24.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

  25.         USART_Init(USART3, &USART_InitStructure);

  26.         USART_ClearFlag(USART3, USART_FLAG_TC);
  27.         USART_Cmd(USART3, ENABLE);

  28. #if USART3_RX_EN
  29.         USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
  30.         NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  31.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  32.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  33.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  34.         NVIC_Init(&NVIC_InitStructure);
  35. #endif
  36. }
复制代码
完成串口的初始化后,就该完成串口的发送,这样才可以为后续的程序调试打下基础,我比较喜欢用的串口发送方式引用了正点原子提供的开发例程中的一段代码:
  1. void u3_printf(char* fmt,...)
  2. {
  3.         u16 i,j;
  4.         va_list ap;
  5.         va_start(ap,fmt);
  6.         vsprintf((char*)USART3_TX_BUF,fmt,ap);
  7.         va_end(ap);
  8.         i=strlen((const char*)USART3_TX_BUF);//此次发送数据的长度
  9.         for(j=0; j<i; j++) //循环发送数据
  10.         {
  11.                 while((USART3->SR&0X40)==0);//循环发送,直到发送完毕
  12.                 USART3->DR=USART3_TX_BUF[j];
  13.         }
  14. }
复制代码
这种串口发送方式虽然消耗了一定的RAM资源,但是可以实现非常灵活的发送方式,顺便还可以实现字符串,数值的格式化发送,和大家学习的C语言中printf方式很相像,在编译的过程中接的勾选keil魔术棒选项里面的USE MicroLIB,如下图所示:
5.png
否则编译后现象不明显。

五、主程序的编写
最后需要编写主程序来测试之前的代码对不对,主程序相对来说就简单了许多,只有寥寥的几行就完了,当然得记得包含各个头文件才行:
  1. #include "stm32f4xx.h"
  2. #include "LED.h"
  3. #include "USART3.h"
  4. #include "delay.h"


  5. int main(void)
  6. {
  7.         LED_Init();
  8.         USART3_Init(115200);
  9.         while(1)
  10.         {
  11.                 LED2^=1;
  12.                 u3_printf("中国电子网技术论坛_bbs.21ic.com\r\n");
  13.                 delay_ms(500);
  14.         }
  15. }
复制代码
主程序中的延时函数在上传的代码中已经包含了,在此不再详述。
通过使用串口调试助手,打开对应的端口号和设置好波特率值,就可以看到数据已经发送到了电脑上:
6.png





 楼主| 湛只为无双 发表于 2015-12-12 17:27 | 显示全部楼层
本帖最后由 湛只为无双 于 2015-12-12 18:13 编辑

这一层楼用于公布源代码工程给大家做参考。

STM32F469_Project.zip

743.32 KB, 下载次数: 36

上述程序的原Keil工程

 楼主| 湛只为无双 发表于 2015-12-12 17:28 | 显示全部楼层
deru_qq 发表于 2015-12-12 20:54 | 显示全部楼层
楼主真快,貌似是第一个
大秦正声 发表于 2015-12-13 20:19 来自手机 | 显示全部楼层
不错。
ElectronF0 发表于 2015-12-14 10:15 | 显示全部楼层
没拿到板子,也要看看
maxiang615 发表于 2015-12-15 08:31 | 显示全部楼层
很羡慕啊           
mega1702 发表于 2016-3-28 11:47 | 显示全部楼层
谢谢楼主分享!!!
西街耳呦 发表于 2017-5-8 20:45 | 显示全部楼层
楼主 屏幕数字和字母可以显示,汉字就显示乱码是什么问题呢,求指教
您需要登录后才可以回帖 登录 | 注册

本版积分规则

15

主题

171

帖子

9

粉丝
快速回复 在线客服 返回列表 返回顶部