STM32 开发入门教程 - 图文

更新时间:2024-05-11 12:38:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

STM32 开发入门教程

(一) 开发环境建立及其应用

入门准备:

我们常用的 STM32 开发编译环境为 Keil 公司的 MDK (Microcontroller Development Kit) 和 IAR 公司的 EWARM.

在这里我们提供了比较稳定的新版本编译软件下载: MDK4.10

限于篇幅, 在我们的教程里面将先以 MDK 下的一个例子来介绍如何使用 MDK 进行嵌入式应用开发.

MDK 安装与配置:

基于 MDK 下的开发中基本的过程: (1) 创建工程; (2) 配置工程;

(3) 用 C/C++ 或者 汇编语言编写源文件; (4) 编译目标应用程序 (5) 修改源程序中的错误 (6) 测试链接应用程序

---------------------------------------------------------------- (1) 创建一个工程:

在 uVision 3 主界面中选择 \-> %uVision Project\菜单项, 打开一个标准对话框选择好你电脑中的保存目录后, 输入一个你的工程名字后点确认.我们的工程中建了一个名字叫 \的工程.

从设备库中选择目标芯片, 我们的 MINI-STM32 开发板使用的是 STM32F103V8T6, 因此选中 STMicrocontroller 下对应的芯片:

ARM 32-bit Cortex-M3 Microcontroller, 72MHz, 64kB Flash, 20kB SRAM, PLL, Embedded Internal RC 8MHz and 32kHz, Real-Time Clock, Nested Interrupt Controller, Power Saving Modes, JTAG and SWD, 3 Synch. 16-bit Timers with Input Capture, Output Compare and PWM, 16-bit 6-ch Advanced Timer, 2 16-bit Watchdog Timers, SysTick Timer, 2 SPI, 2 I2C, 3 USART, USB 2.0 Full Speed Interface, CAN 2.0B Active, 2 12-bit 16-ch A/D Converter, Fast I/O Ports

1

2

选择完芯片型号后会提示是否在目标工程中加入 CPU 的相关的启动代码, 如下图所示. 启动代码是用来初始化目标设备的配置, 完成运行的系统初始化工作, 因此我们选择 \是\这会使系统的启动代码编写工作量大大减少.

---------------------------------------------------------------- (2) 配置工程:

选择菜单中 \或者 选择快捷菜单中的图标:

因为 MINI-STM32 开发板上使用的就是 8M 的晶振且是使用的片内的 RAM 和 ROM 因此 \下我们都可以使用默认的配置;

在\菜单下我们需要选中 \Hex File\来生成编译好的工程代码, 此工程可以通过仿真器或者串口 ISP 烧录进开发板中.

注: ISP 烧录过程我们将在入门教程二中给大家介绍.

\菜单中我们保持默认即可.

\菜单为我们常用的菜单, 这里简单的介绍下他们的具体功能:

PreProcesser Symbols 中的 Define, Undefine 菜单表示是工程的宏定义中的变量, 我们将在今后的教程中详细介绍这个功能.

3

Optimization 为优化选项, Level0 为不优化, 这种模式最适合调试, 因为不会优化掉代码, 基本每个用到的变量都可以打断点. Level3 为优化等级最高, 最适合生产过程中下载到芯片中的代码.

Include Path 为工程中的包含路径, 一般需将 .h 文件或者库文件的地址配置进去.

\和 \将在今后的高级教程中介绍.

\为我们调试使用的配置选项, \为使用软件仿真. 这里根据大家手里的仿真器来选择配置环境.

如果你使用的是 Ulink, 那么就选择 \Cotex Debug\如果你选择的是 JLINK, 那么就选择 \如果你使用的是 ST 公司出的简易仿真器 ST-Link , 那么你就选择 \

注意: 右边当中的选项 \选项如果勾上就表示仿真时进入了就会进入到 main 函数, 如果没有选上就会进入初始地址, 你需要自己打断点运行到你的主程序 main 处.

4

当插上仿真器后选择上面右图中的 Setting 后会跳出一个仿真器的配置菜单. 左边会自动识别出你的仿真器的信息.

如下图为 ULINK2 的信息:

5

对于 SWJ 选项为三线制调试, 将在后面的高级教程中介绍. 右下方有两个选项:

\表示下载后校验数据

\表示当仿真的时候先将目标代码下载到 Flash 中.

Trace 菜单为跟踪配置, 可以实时的将一些变量使用曲线的形式实时表示出来, 我们将在今后的高级教程中介绍这一项功能.

注意: 市面上目前的盗版 Ulink2 不支持这项功能, 正版的支持, Jlink 也不支持这项功能.

\菜单用来配置使用仿真器程序下载的配置选项, 大家务必选择好和你芯片配套的选项. 如果你是使用的别人模板下修改为你的工程, 这个选项请注意一下, 如果不正确将不能将你的代码下载到芯片中.

配置好 \后, 那么 \可以不用配置.

如果你使用的是仿真器仿真, 在你已经正确得将目标板和仿真器建立了物理连接后, 请选择正确的仿真器进行配置.

6

(二) ISP 在线下载程序

ISP:in system programming

简介:

ISP: 用写入器将code烧入,不过,芯片可以在目标板上,不用取出来,在设计目标板的时

候就将接口设计在上面,所以叫\在系统编程\即不用脱离系统;

应用场合: 1,ISP 程序升级需要到现场解决,不过好一点的是不必拆机器了; ISP的实现一般需要很少的外部电路辅助实现,通常可利用单片机的串行口接到计算机

的RS232口,通过专门设计的固件程序来编程内部存储器。

主要是指代芯片的烧写方式,以往写片子需要把片子拿下来,离开电路,用 编程器烧,

换句话说,芯片不能不脱离应用系统进行写入。

ISP 主要针对这个问题,使用JTAG或者串行口(MCU 内部有Boot Loader,通过指定的方式激活之,它可以和PC或其它上位机通过串口联系,不用使单片机离开应用系统而更新

内部的程序/设置)进行程序的烧写操作。

因此,具有ISP 功能的MCU 可以不使用编程器进行编程。当然,实现ISP 可能需要一

些硬件电路支持,具体的在数据手册中有说明。

一般具备ISP 功能后,就不要编程器了,而是使用下载线进行编程工作。但是不是说他们就一定不支持编程器了,具体型号具体分析。是否需要仿真器进行仿真和是否具备ISP和IAP没有必然的联系。只不过具备了IAP功能,可以在MCU内写入监控程序,模拟一个仿真器,当然,这个监控程序是要消耗资源的,和使用硬件的仿真器还有一定的差异。

-------------------------------------------------------------------

以上就是 ISP 的一些概念上的描述, 现在通俗点说就是怎么利用工具把程序下载到芯片

当中去.

第一步: 配置工程, 输出编译后的代码 .Hex 文件:

我们打开第一个我们的教程例子, GPIO_Test 这个例子工程.

先按照下面的步骤来配置一下工程:

7

点击下图中的 Option 选项;

选中 \菜单下的 \并且在右边的 \中

填写我们生成编译代码的文件名称.

配置完选项后, 点击工程编译按钮, 然后我们就可以在

\\Example2-GPIO\\GPIO_test\\output 目录下面得到 Gpio_Test.Hex 文件了.

8

第二步: 准备串口物理连接和 设置 Boot 跳线选择芯片启动类型

先需要准备一根串口延长线, 一头为公头,一头为母头的串口连接线 (非交叉线), 和一台有串口的电脑. (注意:如果您的电脑没有串口,请购买 \转 RS232\的硬件设备来扩

充你电脑的串口.)

将 Mini-STM32 的 J1 跳线帽跳至 2,3 两脚上选择芯片从内部的 Boot 区启动, 上电后会

先进入 ISP 状态. 连接串口线至你的电脑上的串口

将 USB 延长线连接至你的电脑上给 Mini-STM32 开发板供上 5V 电源. 当开发板上的电

源指示灯点亮后一切准备就绪.

第三步: 配置 ISP 下载软件 mcuisp.exe:

您可以点击下载稳定版的 mcuisp V0.975 版本的软件:

打开 mcuisp.exe 绿色软件,

选择好您连接至开发板使用的电脑上的串口, 可以通过搜索串口菜单来自动搜索出你电脑

上的串口信息.

在左上方的\程序文件\选择你准备烧入芯片中的代码, 就是前面我们生成的

Gpio_Test.Hex.

然后在菜单选项栏上选择 \菜单, 点击 \读STM32器件信息\命令按钮.

我们会在右边的信息框中显示出连接成功的信息:

如图所示:

mcuisp.rar (576.58 KB)

9

选择上\校验\和\编程后运行\两个选项后点击\开始编程\会报出程序成功烧入芯片的一些信息, 如下:

------------------------------------------------------------------ DTR电平置高(+3-+12V),复位

RTS置高(+3-+12V),选择进入BootLoader ...延时100毫秒

DTR电平变低(-3--12V)释放复位 RTS维持高

开始连接...3, 接收到:1F

在串口COM4连接成功@115200bps,耗时343毫秒 芯片内BootLoader版本号:2.1 芯片PID:00000410 芯片FLASH容量为128KB

芯片SRAM容量为65535KB(此信息仅供参考,新版本芯片已不包含此信息) 96位的芯片唯一序列号:33006C065839353235581943 读出的选项字节:

A55AFF00FF00FF00FF00FF00FF00FF00 全片擦除成功

第547毫秒,已准备好

共写入2KB,进度100%,耗时4343毫秒 成功从08000000开始运行

www.mcuisp.com向您报告,命令执行完毕,一切正常

----------------------------------------------------------------

这个时候您可以看到您手中的 Mini-STM32 开发板上的两个红色 LED 有规律的轮流点亮, 说明程序已经成功的烧入芯片了.

10

最后您在断电后将 Mini-STM32 上 J1 的跳线帽跳至 1,2 引脚上, 重新上电后, 程序就可以正常运行了.

(三) 系统时钟 SysTick

(一) 背景介绍

在传统的嵌入式系统软件按中通常实现 Delay(N) 函数的方法为:

for(i = 0; i <= x; i ++);

x --- 对应于 对应于 N 毫秒的循环值

对于STM32系列微处理器来说,执行一条指令只有几十个 ns,进行 for 循环时,要实现 N 毫秒的 x 值非常大,而且由于系统频率的宽广,很难计算出延时 N 毫秒的精确值。针对 STM32 微处理器,需要重新设计一个新的方法去实现该功能,以实现在程序中使用 Delay(N)。

(二) STM32 SysTick 介绍

Cortex-M3 的内核中包含一个 SysTick 时钟。SysTick 为一个 24 位递减计数器,SysTick 设定初值并使能后,每经过 1 个系统时钟周期,计数值就减 1。计数到 0 时,SysTick 计数器自动重装初值并继续计数,同时内部的 COUNTFLAG 标志会置位,触发中断 (如果中断使能情况下)。

在 STM32 的应用中,使用 Cortex-M3 内核的 SysTick 作为定时时钟,设定每一毫秒产生一次中断,在中断处理函数里对 N 减一,在Delay(N) 函数中循环检测 N 是否为 0,不为 0 则进行循环等待;若为 0 则关闭 SysTick 时钟,退出函数。

注: 全局变量 TimingDelay , 必须定义为 volatile 类型 , 延迟时间将不随系统时钟频率改变。

11

(三) ST SysTick 库文件

使用ST的函数库使用systick的方法

1、调用SysTick_CounterCmd() -- 失能SysTick计数器 2、调用SysTick_ITConfig () -- 失能SysTick中断 3、调用SysTick_CLKSourceConfig() -- 设置SysTick时钟源。 4、调用SysTick_SetReload() -- 设置SysTick重装载值。 5、调用SysTick_ITConfig () -- 使能SysTick中断 6、调用SysTick_CounterCmd() -- 开启SysTick计数器

(四) SystemTick 工程实战

外部晶振为 8 MHz,9 倍频,系统时钟为 72MHz,SysTick 的最高频率为9MHz(最大为HCLK / 8),在这个条件下,把 SysTick 效验值设置成9000,将 SysTick 时钟设置为 9 MHz, 就能够产生 1ms 的时间基值,即 SysTick 产生 1ms 的中断。

/* Configure the system clocks */ RCC_Configuration(); SysTick_Configuration();

第一步: 配置 RCC 寄存器 和 SysTick 寄存器

RCC_Configuration: 配置 RCC 寄存器 void RCC_Configuration(void) {

/* RCC system reset(for debug purpose) */ RCC_DeInit();

/* Enable HSE */

RCC_HSEConfig(RCC_HSE_ON);

/* Wait till HSE is ready */

12

HSEStartUpStatus = RCC_WaitForHSEStartUp();

if(HSEStartUpStatus == SUCCESS) {

/* HCLK = SYSCLK */

RCC_HCLKConfig(RCC_SYSCLK_Div1);

/* PCLK2 = HCLK */

RCC_PCLK2Config(RCC_HCLK_Div1);

/* PCLK1 = HCLK/2 */

RCC_PCLK1Config(RCC_HCLK_Div2);

/* Flash 2 wait state */

FLASH_SetLatency(FLASH_Latency_2); /* Enable Prefetch Buffer */

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

/* PLLCLK = 8MHz * 9 = 72 MHz */

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

/* Enable PLL */ RCC_PLLCmd(ENABLE);

/* Wait till PLL is ready */

while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { }

/* Select PLL as system clock source */ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

/* Wait till PLL is used as system clock source */ while(RCC_GetSYSCLKSource() != 0x08) { }

13

}

/* Enable GPIOA and AFIO clocks */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); }

SysTick_Configuration: 配置 SysTick

void SysTick_Configuration(void) {

/* Select AHB clock(HCLK) as SysTick clock source */ SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);

/* Set SysTick Priority to 3 */

NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 3, 0);

/* SysTick interrupt each 1ms with HCLK equal to 72MHz */ SysTick_SetReload(72000);

/* Enable the SysTick Interrupt */ SysTick_ITConfig(ENABLE); }

第二步: 配置 SysTick 中断函数

这里我们定义了一个 TestSig 全局变量, 用于我们使用 Keil 软件自带的逻辑分析仪来分析.

volatile vu32 TimingDelay = 0; vu8 TestSig = 0;

14

void SysTickHandler(void) {

TimingDelay--; if(TimingDelay % 2) {

TestSig = 1; } else {

TestSig = 0; } }

第三步: 编写 Delay 延时函数

Delay: 系统延时函数, 使用系统时钟操作.

void Delay(u32 nTime) {

/* Enable the SysTick Counter */

SysTick_CounterCmd(SysTick_Counter_Enable);

TimingDelay = nTime;

while(TimingDelay != 0);

/* Disable the SysTick Counter */

SysTick_CounterCmd(SysTick_Counter_Disable); /* Clear the SysTick Counter */

SysTick_CounterCmd(SysTick_Counter_Clear); }

第四步: 主函数中调用 Delay

15

在 Mini-STM32 开发板上有两个 LED 灯, 分别是 PA0, PA1. 我们做个流水灯程序, 让他们循环点亮. while(1) {

GPIO_SetBits(GPIOA,GPIO_Pin_0); Delay(100);

GPIO_ResetBits(GPIOA,GPIO_Pin_0); Delay(100);

GPIO_SetBits(GPIOA,GPIO_Pin_1); Delay(100);

GPIO_ResetBits(GPIOA,GPIO_Pin_1); Delay(100); }

(五) 仿真调试

把工程便宜通过后, 进入软件仿真

如下图所示:点击工程快捷菜单的逻辑分析仪

在逻辑分析仪中我们点击 Setup 按键会弹出安装对话框.

点右上方的 \新建\图标, 在菜单中输入 \这个全局变量.

添加完之后就可以点 Close 了. 如果您仿真完可以点击 左下方的 \删除所有监视变量.

16

全速运行后就可以看到下面的波形了哦

17

如果你使用仿真器在 Mini-STM32 上调试的话你还可以看到两个 LED 在跑跑马灯程序了. 到此我们这章节的教程就结束了, 相信大家也掌握了 System Tick 的用法了.

(四) GPIO简单应用和外部中断

这个章节我们将学习最基本的 STM32 的 GPIO 的应用. 我们将分为两个章节来学习.

第一部份: GPIO 的基本应用和 IO 口的配置 第二部份: 外部中断的使用

--------------------------------------------------------------------------

1: 设计要求:

开发板上有 2 个 LED, 我们的目的为有规律的点亮 LED1 和 LED2. 当按键按下去的时候所有的灯灭, 等待 2 秒钟后恢复有规律的点亮.

18

2: 硬件电路:

3: 软件程序设计:

(1) 根据要求配置 GPIOA 中的 PA0,PA1 为输出, PA3, PA8 为输入

对于下面程序中的 GPIO_InitStructure.GPIO_Speed 和 GPIO_InitStructure.GPIO_Mode 推荐大家看下面两篇文章.

STM32 GPIO的十大优越功能综述

备注: 当STM32的GPIO端口设置为输出模式时,有三种速度可以选择:2MHz、10MHz和50MHz,这个速度是指I/O口驱动电路的速度,是用来选择不同的输出驱动模块,达到最佳的噪声控制和降低功耗的目的。

STM32 GPIO端口的输出速度设置

备注: 共有8种模式,可以通过编程选择: 1. 浮空输入 2. 带上拉输入 3. 带下拉输入 4. 模拟输入

5. 开漏输出——(此模式可实现hotpower说的真双向IO) 6. 推挽输出

7. 复用功能的推挽输出 8. 复用功能的开漏输出

模式7和模式8需根据具体的复用功能决定。

void GPIO_Configuration(void)

19

{

GPIO_InitTypeDef GPIO_InitStructure;

/* Configure PA. as Output push-pull */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, GPIO_InitStructure);

/* Configure PA3,PA8 as input floating (EXTI Line3 , EXTI Line8) */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); }

(2) 打开 GPIOA 的时钟, 因为 STM32 是一个低功耗的 MCU , 每一个你使用的外围设备都需要单独开启时钟, 如果不开启将不能使用, 这个也是对于 STM32 初学者容易疏忽的地方

/* Enable GPIOA and AFIO clocks */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |

RCC_APB2Periph_AFIO, ENABLE);

STM32共有5种时钟源,其中三种不同的时钟源可用作为驱动系统时钟(SYSCLK);

1、HSI 由内部8MHz RC振荡器产生,它是可以直接用来作为系统时钟或经2分频后作为PLLSRC输入。

HIS时钟频率在出厂时被校准在1%(25°C),在系统复位时,工厂校准值会被装载到时钟控制寄存器的HISCAL[7..0] 位。

用户可以通过更改HISCAL[4..0]来调整HSI频率。 另外时钟寄存器中有一个HSIRDY位用来指示HSI RC是不稳定工作,在时钟启过后,直到这个标志位置被硬件置1后,HSI RC时钟才被输出。

HSI RC时钟还可以用时钟寄存器中的HSION位来启动和关闭。

HSI时钟同时也是HSE晶体荡振器的备用时钟源。

使用HSE时钟,程序设置时钟参数流程:

1、将RCC寄存器重新设置为默认值 RCC_DeInit;

2、打开外部高速时钟晶振HSE RCC_HSEConfig(RCC_HSE_ON);

3、等待外部高速时钟晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp(); 4、设置AHB时钟 RCC_HCLKConfig; 5、设置高速AHB时钟 RCC_PCLK2Config; 6、设置低速速AHB时钟 RCC_PCLK1Config; 7、设置PLL RCC_PLLConfig;

8、打开PLL RCC_PLLCmd(ENABLE);

9、等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)

20

10、设置系统时钟 RCC_SYSCLKConfig;

11、判断是否PLL是系统时钟 while(RCC_GetSYSCLKSource() != 0x08)

12、打开要使用的外设时钟 RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()

具体设置请参考下面的文章

STM32时钟系统与软件配置

STM32的时钟系统分析

STM32 的时钟与RTC

(3) 设置外部中断, 所有的 GPIO 口都可以作为外部中断源. 具体可以参考下面这篇文章.

STM32中外部中断与外部事件

/* Connect EXTI Line3 to PA.3 */

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);

/* Configure EXTI Line3 to generate an interrupt on falling edge */ EXTI_InitStructure.EXTI_Line = EXTI_Line3;

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(EXTI_InitStructure);

同样不要忘记打开时钟, 我们在打开 PA 口的时候已经加上了 RCC_APB2Periph_AFIO, 这里再提醒大家一下.

/* Enable GPIOA and AFIO clocks */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |

RCC_APB2Periph_AFIO, ENABLE);

最后就是编写外部中断入口函数. void EXTI3_IRQHandler(void) {

int i;

if(EXTI_GetITStatus(EXTI_Line9) != RESET) {

GPIO_SetBits(GPIOA,GPIO_Pin_0); GPIO_SetBits(GPIOA,GPIO_Pin_1);

for(i=0;i<=8000000;i++);

21

GPIO_ResetBits(GPIOA,GPIO_Pin_0); GPIO_ResetBits(GPIOA,GPIO_Pin_1);

for(i=0;i<=1000000;i++)

/* Clear the EXTI line 3 pending bit */ EXTI_ClearITPendingBit(EXTI_Line3); } }

不要忘记在中断函数处理完成后清掉标志位,不然会不停的进入中断.

(4) 编译与调试

我们已经完成所有程序编写部份, 接下来就是将工程编译成功后下载到我们的 Mini-STM32 开发板中进行调试和仿真.

如果看到 LED 有规律的点亮和熄灭, 按下按钮后 LED 先是一起熄灭, 在一起点亮, 然后恢复有规律的点亮这个过程, 说明我们已经达到我们的设计目标.

--------------------------------------------------------------------------

总结: 我们学习完了这篇教程之后, 相信大家对下面几个方面的内容已经掌握了. * GPIO 的设置

* STM32 GPIO 的优势 * STM32 的时钟结构 * 外部中断的配置

* 外部中断和外部事件的区别

(五) 异步串口双工通讯

(一) STM32 的 USART 模拟介绍

通用同步异步收发器(USART)提供了一种灵活的方法来与使用工业标准NR 异步串行数据格式的外部设备之间进行全双工数据交换。 USART利用分数波特率发生器提供宽范围的波特率选择。

22

它支持同步单向通信和半双工单线通信。它也支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。用于多缓冲器配置的DMA方式,可以实现高速数据通信。

主要特性:

全双工的,异步通信 NR 标准格式

分数波特率发生器系统

-发送和接收共用的可编程波特率,最高到4.5Mbits/s 可编程数据字长度(8位或9位)

可配置的停止位 -支持1或2个停止位

LIN主发送同步断开符的能力以及LIN从检测断开符的能力

- 当USART硬件配置成LIN时,生成13位断开符;检测10/11位断开符 发送方为同步传输提供时钟 IRDA SIR 编码器解码器

- 在正常模式下支持3/16位的持续时间 智能卡模拟功能

- 智能卡接口支持ISO7816 -3标准里定义的异步协议智能卡 - 智能卡用到的0.5和1.5个停止位 单线半双工通信

使用DMA的可配置的多缓冲器通信

- 在保留的SRAM里利用集中式DMA缓冲接收/发送字节 单独的发送器和接收器使能位 检测标志

- 接收缓冲器满 - 发送缓冲器空 - 传输结束标志 校验控制

- 发送校验位 - 对接收数据进行校验 四个错误检测标志 - 溢出错误 - 噪音错误 - 帧错误 - 校验错误 10个带标志的中断源

23

- CTS改变 - LIN断开符检测 - 发送数据寄存器 - 发送完成 - 接收数据寄存器 - 检测到总线为空 - 溢出错误 - 帧错误 - 噪音错误 - 校验错误

多处理器通信 - - 如果地址不匹配,则进入静默模式 从静默模式中唤醒(通过空闲总线检测或地址标志检测) 两种唤醒接收器的方式 - 地址位(MSB) - 空闲总线

(二) 程序编写

(1) 在 RCC_Configuration 函数中, 打开串口时钟 /* Enable USART1, GPIOA, GPIOx and AFIO clocks */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA RCC_APB2Periph_GPIOx

| RCC_APB2Periph_AFIO, ENABLE);

(2) 设置串口的 RTX, TDX IO 口的属性 void GPIO_Configuration(void) {

GPIO_InitTypeDef GPIO_InitStructure;

/* Configure USART1 Rx (PA.10) as input floating */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure);

24

|

/* Configure USART1 Tx (PA.09) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, GPIO_InitStructure); }

(3) 移植 fputc 函数 int fputc(int ch, FILE *f) {

/* Place your implementation of fputc here */ /* e.g. write a character to the USART */ USART_SendData(USART1, (u8) ch);

/* Loop until the end of transmission */

while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) { }

return ch; }

(4) 主函数中初始化串口设置

USART_ClockInitStructure.USART_Clock = USART_Clock_Disable; USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low; USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge; USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable; /* Configure the USART1 synchronous paramters */ USART_ClockInit(USART1, USART_ClockInitStructure);

USART_InitStructure.USART_BaudRate = 115200;

USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No ;

25

USART_InitStructure.USART_HardwareFlowControl =

USART_HardwareFlowControl_None;

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; /* Configure USART1 basic and asynchronous paramters */ USART_Init(USART1, USART_InitStructure);

/* Enable USART1 */ USART_Cmd(USART1, ENABLE);

(5) 编写应用程序

printf(\欢迎来到麦思网论坛 \\r\\n\ printf(\http://www.mystm32.com \\r\\n\

printf(\ while(1 ) {

if(USART_GetFlagStatus(USART1,USART_IT_RXNE)==SET) {

i = USART_ReceiveData(USART1);

printf(\ } }

(三) 调试仿真程序

(1) 使用Keil uVision3 通过ULINK 2仿真器连接实验板,打开实验例程目录USART_TEST子目录下的USART.Uv2例程,编译链接工程;

(2) 使用MINI-STM32开发板附带的串口线,连接开发板上的COM和PC机的串口; (3) 在PC机上运行windows自带的超级终端串口通信程序(波特率115200、1位停止位、无校验位、无硬件流控制);或者使用其它串口通信程序;

26

(4) 选择硬件调试模式,点击MDK 的Debug菜单,选择Start/Stop Debug Session项或Ctrl+F5键,远程连接目标板并下载调试代码到目标系统中; (5) 例程正常运行之后会在超级终端显示以下信息: \欢迎来到麦思网论坛\\http://www.mystm32.com\

\

在PC机的键盘上输入的字符,将在超级终端上显示。

(6) 也可选择软件调试模式,点击MDK 的Debug菜单,打开串行窗口,选择Start/Stop Debug Session

项或Ctrl+F5键,在串行窗口中也可看到与第(5)步超级终端中所显示的相同内容。

使用软件调试可以参考贴子:

[原创] MDK 下使用 Serial Windows 调试串口教程

(六) 基于 DMA 的 ADC

27

(一) STM32 ADC 模块介绍

28

(二) 程序编写 (1) 设置 ADC 的地址

#define ADC1_DR_Address ((u32)0x4001244C)

(2) 初始化 DMA 和 ADC 模块与应用程序

/* DMA channel1 configuration ----------------------------------------------*/ DMA_DeInit(DMA1_Channel1);

DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; // 外设地址 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue; // 内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // DMA 传输方向单向 DMA_InitStructure.DMA_BufferSize = 1; // 设置DMA在传输时缓冲区的长度 word DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //设置DMA外设递增模式

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; // 设置DMA内存递增模式 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 外设数据字长

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //内存数据字长

29

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 设置传输模式连续不断的循环模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 设置DMA的优先级别

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 设置DMA的2个memory中的变量互相访问

DMA_Init(DMA1_Channel1, DMA_InitStructure);

/* Enable DMA channel1 */ DMA_Cmd(DMA1_Channel1, ENABLE);

/* ADC1 configuration ------------------------------------------------------*/ ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立工作模式 ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 扫描方式 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 外部触发禁止 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1; // 用于转换的通道数 ADC_Init(ADC1, ADC_InitStructure);

/* ADC1 regular channel14 configuration */

ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_55Cycles5);

/* Enable ADC1 DMA */ ADC_DMACmd(ADC1, ENABLE);

/* Enable ADC1 */ ADC_Cmd(ADC1, ENABLE);

/* Enable ADC1 reset calibaration register */ ADC_ResetCalibration(ADC1);

/* Check the end of ADC1 reset calibration register */ while(ADC_GetResetCalibrationStatus(ADC1));

/* Start ADC1 calibaration */ ADC_StartCalibration(ADC1);

/* Check the end of ADC1 calibration */ while(ADC_GetCalibrationStatus(ADC1));

30

/* Start ADC1 Software Conversion */ ADC_SoftwareStartConvCmd(ADC1, ENABLE);

while(1) {

AD_value = ADC_GetConversionValue(ADC1);

delay(); }

(三) 仿真调试

(1) 使用Keil uVision3 通过ULINK 2仿真器连接实验板,使用MINI-STM32 开发板附带的串口线,连接实验板上的 UART1 和 PC 机的串口,打开实验例程目录下的ADC.Uv2例程,编译链接工程;

(2) 在 PC 机上运行 windows 自带的超级终端串口通信程序(波特率115200、1位停止位、无校验位、无硬件流控制);或者使用其它串口通信程序; (3) 点击MDK 的Debug菜单,点击Start/Stop Debug Session;

(4) 旋转电位器 R19,可以看到串口输出数值不断变化,正常显示结果如下所示。

usart1 print AD_value -------------------------- The current AD value = 0x0425 The current AD value = 0x0423 The current AD value = 0x0421 The current AD value = 0x0422 The current AD value = 0x0420 The current AD value = 0x0416 The current AD value = 0x03B6 The current AD value = 0x0841 The current AD value = 0x08C3 The current AD value = 0x08C0 The current AD value = 0x08BE The current AD value = 0x09E9 The current AD value = 0x0A12

31

The current AD value = 0x0ACA The current AD value = 0x0B0D The current AD value = 0x0B10 The current AD value = 0x0B0E .... ....

(5) 若无开发板,读者也可以使用软件仿真模式来完成程序运行。

MINI-STM32 开发板入门教程 (七) - 工业现场总线 CAN

(七) - 工业现场总线 CAN

32

(一) 工业现场总线 CAN 的基本介绍以及 STM32 的 CAN 模块简介

首先通读手册中关于CAN的文档,必须精读。 STM32F10xxx 参考手册Rev7V3.pdf

http://www.mystm32.com/bbs/redirect.php?tid=255goto=lastpost#lastpost

需要精读的部分为 RCC 和 CAN 两个章节。

为什么需要精读 RCC 呢?因为我们将学习 CAN 的波特率的设置,将要使用到 RCC 部分的设置,因此推荐大家先复习下这部分中的几个时钟。

关于 STM32 的 can 总线简单介绍

bxCAN 是基本扩展 CAN (Basic Extended CAN) 的缩写,它支持 CAN 协议 2.0A 和 2.0B 。它的设计目标是,以最小的 CPU 负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性可软件配置)。

对于安全紧要的应用,bxCAN 提供所有支持时间触发通信模式所需的硬件功能。 主要特点

2 支持 CAN 协议 2.0A 和 2.0B 主动模式 2 波特率最高可达 1 兆位 / 秒 2 支持时间触发通信功能 发送

2 3 个发送邮箱

2 发送报文的优先级特性可软件配置 2 记录发送 SOF 时刻的时间戳 接收

2 3 级深度的2个接收 FIFO

2 14 个位宽可变的过滤器组 - 由整个 CAN 共享 2 标识符列表

2 FIFO 溢出处理方式可配置 2 记录接收 SOF 时刻的时间戳

可支持时间触发通信模式 2 禁止自动重传模式

33

2 16 位自由运行定时器 2 定时器分辨率可配置

2 可在最后 2 个数据字节发送时间戳 管理

2 中断可屏蔽

2 邮箱占用单独 1 块地址空间,便于提高软件效率

(二) STM32 CAN 模块工作模式

STM32 的 can 的工作模式分为: /* CAN operating mode */

#define CAN_Mode_Normal ((u8)0x00) /* normal mode */ #define CAN_Mode_LoopBack ((u8)0x01) /* loopback mode */ #define CAN_Mode_Silent ((u8)0x02) /* silent mode */ #define CAN_Mode_Silent_LoopBack ((u8)0x03) /* loopback combined with silent mode */

在此章我们的 Mini-STM32 教程中我们将使用到 CAN_Mode_LoopBack 和 CAN_Mode_Normal 两种模式。

我们第一步做的就是使用运行在 CAN_Mode_LoopBack 下进行自测试。

在参考手册中 CAN_Mode_LoopBack (环回模式) 的定义如下:

环回模式可用于自测试。为了避免外部的影响,在环回模式下 CAN 内核忽略确认错误 (在数据 / 远程帧的确认位时刻,不检测是否有显性位) 。在环回模式下,bxCAN 在内部把 Tx 输出回馈到 Rx 输入上,而完全忽略 CANRX 引脚的实际状态。发送的报文可以在 CANTX 引脚上检测到。

因此这种模式也特别适合大家做好硬件后自测程序。

34

(三) CAN 接口端口映射

STM32 中的 CAN 物理引脚脚位可以设置成三种:默认模式,重定义地址1模式,重定义地址2模式。

在我们的 Mini-STM32 上面没有接出 CAN 的接口芯片, 所以我们可以利用 RealView MDK 的 CAN 软件模拟模块来做实验.

------------------------------------------------------------------------- 默认模式

/* Configure CAN pin: RX */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, GPIO_InitStructure);

35

/* Configure CAN pin: TX */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, GPIO_InitStructure);

------------------------------------------------------------------------ 重定义地址1模式

/* Configure CAN pin: RX */

//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //GPIO_Init(GPIOB, GPIO_InitStructure);

/* Configure CAN pin: TX */

//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //GPIO_Init(GPIOB, GPIO_InitStructure);

/* Configure CAN Remap 重影射 */

//GPIO_PinRemapConfig(GPIO_Remap1_CAN, ENABLE);

------------------------------------------------------------------------- 重定义地址2模式

/* Configure CAN pin: RX */

//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //GPIO_Init(GPIOD, GPIO_InitStructure);

/* Configure CAN pin: TX */

//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //GPIO_Init(GPIOD, GPIO_InitStructure);

/* Configure CAN Remap 重影射 */

36

//GPIO_PinRemapConfig(GPIO_Remap2_CAN, ENABLE);

-------------------------------------------------------------------------

设置完 CAN 的引脚之后还需要打开 CAN 的时钟: /* CAN Periph clock enable */

RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN, ENABLE);

(四) CAN 波特率设置

4、我们需要搞明白CAN波特率的设置,这个章节也是使用CAN的最重要的部分之一,因为这实际应用中我们需要根据我们实际的场合来选择 CAN 的波特率。 一般情况下面1M bps 的速率下可以最高可靠传输 40 米以内的距离。 在 50K 以下的波特率中一般可以可靠传输数公里远。

对于波特率的设置需要详细学习参考手册对应部分的解释。我们在调试软件的时候可以使用示波器来测试 CANTX 引脚上的波形的波特率,这样可以得到事半功倍的效果,大大的缩短调试学习的时间。

// *************************************************************** // BaudRate = 1 / NominalBitTime // NominalBitTime = 1tq + tBS1 + tBS2 // tq = (BRP[9:0] + 1) x tPCLK // tPCLK = CAN's clock = APB1's clock

// ****************************************************************

也就是BaudRate = APB1 / ((BS1 + BS2 + 1) * Prescaler)

这里注意的是采用点的位置,也就时BS1,BS2的设置问题,这里我也找了一些资料,抄录下来给大家,是 CANopen 协议中推荐的设置。

1Mbps 速率下,采用点的位置在6tq位置处,BS1=5, BS2=2 500kbps 速率下,采用点的位置在8tq位置处,BS1=7, BS2=3 250kbps 速率下,采用点的位置在14tq位置处,BS1=13, BS2=2 125k, 100k, 50k, 20k, 10k 的采用点位置与 250K 相同。

因此我们需要重视的有软件中的这么几个部分:

// 设置 AHB 时钟(HCLK)

37

// RCC_SYSCLK_Div1 AHB 时钟 = 系统时钟 RCC_HCLKConfig(RCC_SYSCLK_Div8);

// 设置低速 AHB 时钟(PCLK1)

// RCC_HCLK_Div2 APB1 时钟 = HCLK / 2 RCC_PCLK1Config(RCC_HCLK_Div2);

// PLLCLK = 8MHz * 8 = 64 MHz // 设置 PLL 时钟源及倍频系数

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_8);

CAN 波特率设置中需要的就是PCLK1 的时钟。

CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack; CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; CAN_InitStructure.CAN_BS1=CAN_BS1_8tq; CAN_InitStructure.CAN_BS2=CAN_BS2_7tq; CAN_InitStructure.CAN_Prescaler=5;

通过上面部分的时钟设置我们已经可以算出我们的波特率了 CAN_bps = PCLK1 / ((1 + 7 + 8) * 5) = 25K bps

大家也可以实际测试中修改时钟值来通过示波器测试我们需要的波特率是否正确例如将PLLCLK 设置降低一半:

// PLLCLK = 8MHz * 4 = 32 MHz // 设置 PLL 时钟源及倍频系数

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_4);

那么我们得到的CAN_bps也会降低一半。

接下来还可以修改 HCLK 和 PCLK1 ,其实最终这几个分频和倍频值最终影响的都是 PCLK1。

通过几次试验,相信大家应该很容易掌握波特率的设置了。

设置完波特率我们直接测试函数:

38

/* CAN transmit at 100Kb/s and receive by polling in loopback mode*/ TestRx = CAN_Polling();

if (TestRx == FAILED) {

/* Turn on led connected to PA.00 pin (LD1) */ GPIO_SetBits(GPIOA, GPIO_Pin_0); } else {

/* Turn off led connected to PA.00 pin (LD1) */ GPIO_ResetBits(GPIOA, GPIO_Pin_0); }

/* CAN transmit at 500Kb/s and receive by interrupt in loopback mode*/ TestRx = CAN_Interrupt();

if (TestRx == FAILED) {

/* Turn on led connected to PA.01 pin (LD2) */ GPIO_SetBits(GPIOA, GPIO_Pin_1); } else {

/* Turn off led connected to PA.01 pin (LD2) */ GPIO_ResetBits(GPIOA, GPIO_Pin_1); }

将 CAN 软件仿真模拟器 调用出来.

39

大家可以仿真程序,当程序中 Test 等于 Passed 那么说明 Loopback 模式测试通过了。 并且在 CAN 通讯框中我们可以看到发送和接收到的数据:

40

本文来源:https://www.bwwdw.com/article/sn7g.html

Top