So Tired !_! 逆水行舟, 不进则退!

25May/10

使用Keil的命令行编译C51源码并生成HEX文件的示例

Posted by Nick Xu

参考KeilC51HLPC51.pdf以及A51.pdf文档,示例及说明如下:
set PATH=%PATH%;G:developkeilC51BIN;G:developkeilC51INC;G:developkeilC51LIB
set C51_LIB=G:developkeilC51LIB
(注:其中的G:developkeil目录要改成本机安装keil的位置)
set DST_NAME=objoutput (注:指定输出文件名)
set DIR=D:source (注:指定源文件所在目录)

echo 转向工作目录
d: (注:源文件所在区)
cd %DIR%

echo 编译文件...
c51 a.c
c51 b.c
c51 c.c
c51 d.c

md obj
echo 链接目标文件...
BL51 %C51_LIB%C51s.lib,a.obj,b.obj,c.obj,d.obj,EXTERN_LIB.obj TO %DST_NAME% RAMSIZE(256) CODE(?CO?c(FC00H), ?CO?d(FFD0H))
(注:EXTERN_LIB.obj文件是已经编译好的obj文件,用于编译部分模块只有目标代码的项目,RAMSIZE等是一些链接设置,详细信息请参 考C51HLPA51.pdf)

echo 生成HEX文件...
OH51 %DST_NAME%

echo 编译结束
cd

Tagged as: , , No Comments
25May/10

Eclipse和单片机开发环境Keil的集成编译工具KeilMake 使用详细教程

Posted by Nick Xu

Eclipse和单片机开发环境Keil的集成编译工具KeilMake
通过KeilMake可以在Eclipse上进行单片机开发且编译
使用方法:
配置Eclipse中项目Builder Settings的编译命令为
D:MyWorkSCMKeilMakeReleaseKeilMake D:MyWorkDevToolscommandkeilAT89S52.Uv2 ${ProjName} ${ProjDirPath} C:KeilUV2uv2.exe

红色部份修改为程序相应的路径即可,在Eclipse中写完程序后按Ctrl+B即可编译

AT89S52.Uv2 是Keil项目的模板文件,可根据个人需要进行修改,自带的模板配置是
AT89S52芯片,晶振为24Mhz,自动生成Hex文件

近期本人使用Keil进行单片机程序开发,感觉超不爽,在微软长期毒害下,我相信大部分跟着VS做开发的人们都对微软IDE的智能过于依赖。所以最 终我选择了Eclipse,虽然和微软的IDE相比还是有很大差距,不过对于我要做单片机开发的工作应该也可以满足了。在网上并没有找到Eclipse和 Keil可以很好集成在一起的插件,无而之下只好自己动手,搞搞科研了。

KeilMake就是这次的科研成果了,现与大家共同分享。

如果你的芯片和我现在用的一样是AT89S52,24Mhz,那么直接按照上面的方法即可使用,下面的内容可以略过。

如果是其它芯片,又和我一样想用Eclipse来进行单片机开发,那么请跟着我一步一步的操作。

环境安装,安装好Keil和Eclipse下面是我安装两个软件的版本

最新片Eclipse可以到这个地址 www.eclipse.org/downloads/ 下载C/C++版本的即可。

两个软件都安装好后我们就可以开始建立Keil模板了。

首先我们要知道自己的芯片的型号等信息,这里以举个AT89S52的例子,首先在Keil创建一个新项目

我们把项目文件保存为 stc89c52.Uv2 等会需要用到这个文件

CPU类型选择Atmel下面的AT89S52

新增加一个TEST.C的文件,内容空白就行了,因为我们不是在写代码,我们只是创建模板。

点击上面框框中的按钮对项目进行设置。

输入晶振的频率,我这块芯片是24MHz的。

设置生成时创建16进制文件,格式选择HEX-80

接下来用记事本打开刚才我们创建的项目文件 stc89c52.Uv2 留意红色框框的地方,这两个地方是我们需要修改的

File 1,1,<.test.c><test.c> 0x0  修改为 {CodeList}

stc89c52 修改为 {FileName}

完成上面步骤后,模板就创建完成了,我们把 stc89c52.Uv2 复制到别的地方,我放到D:MyWorkDevToolscommandkeil下

我把KeilMake.exe也放到这里了,这个不是必要的,我只是为了方便而已。

好了,现在到Eclipse了,如果在Eclipse上创建Keil项目呢?这里需要更正一个问题,我们不需要在Eclipse上创建Keil项 目,只要创建C项目就可以了,因为 KeilMake.exe 的工作就是把Eclipse上创建的C项目拿到Keil下去编译生成。

创建一个C项目

项目名称:testKeilProject

这里项目类型我选择Empty Project是因为我不需要用到MinGW GCC的类库,所以我选择空项目,然后Toolchains选择Other Toolchain,这一步我们可以直接点击Finish了。

现在到了最关键的设置时刻了,打开项目属性设置窗口。

Build command的值:D:MyWorkDevToolscommandkeilKeilMake.exe D:MyWorkDevToolscommandkeilstc89c52.Uv2 ${ProjName} ${ProjDirPath} C:KeilUV2uv2.exe

下面我们解释一下这行命令的意思

D:MyWorkDevToolscommandkeilKeilMake.exe KeilMake的路径。

D:MyWorkDevToolscommandkeilstc89c52.Uv2 我们刚才创建的Keil模板,以后只要是使用相同芯片做开发就可以使用这个模板。

${ProjName} 是Eclipse中的生成变量,是Eclipse里的项目名称,生成的HEX就是以这个值来命名。

${ProjDirPath} 是Eclipse中的项目目录

C:KeilUV2uv2.exe 是Keil的主程序路径

还有这里红色框框要留空,原值是all

点击File system按钮选择Keil目录下的c51inc目录

完成这一步后,基本上都完成了,我们来写一个程序测试一下。

Eclipse的自动完成功能

很简单的代码,来测试一下编译功能CTRL+B,记得要先保存再按CTRL+B,我刚开始时经常范这个错,所以代码没有编译到。

红色框框是编译生成输出的信息,看到

0 Error

creating hex file from "stc89c52"

这两行就是程序已经编译完成,在项目目录下会看到 stc89c52.hex 文件,把这个文件刷到单片机上试试看?

KeilMake是我学C语言的第一个程序,可能会存在一些BUG,如果使用过程中遇到什么问题,请随时和我联系,可发邮件到我的邮 箱:nick#workao.org 把#换为@

完。

附 KeilMake 下载地址:

KeilMake

25May/10

单片机 常用到的查询资料整理

Posted by Nick Xu

中断优先级及原理图

IE.0 0 外部中断0
IE.1 1 定时器0 溢出
IE.2 2 外部中断1
IE.3 3 定时器1 溢出
IE.4 4 串口中断
IE.5 5 定时器2 溢出

TCON

IT0(TCON.0),外部中断0触发方式控制位。
当IT0=0时,为电平触发方式。
当IT0=1时,为边沿触发方式(下降沿有效)。
IE0(TCON.1),外部中断0中断请求标志位。
IT1(TCON.2),外部中断1触发方式控制位。
IE1(TCON.3),外部中断1中断请求标志位。
TF0(TCON.5),定时/计数器T0溢出中断请求标志位。
TF1(TCON.7),定时/计数器T1溢出中断请求标志位。

SCON

RI(SCON.0),串行口接收中断标志位。当允许串行口接收数据时,每接收完一个串行帧,由硬件置位RI。注意,RI必须由软件清除。
TI(SCON.1),串行口发送中断标志位。当CPU将一个发送数据写入串行口发送缓冲器时,就启动了发送过程。每发送完一个串行帧,由硬件置位TI。 CPU响应中断时,不能自动清除TI,TI必须由软件清除。

IE

EX0(IE.0),外部中断0允许位;
ET0(IE.1),定时/计数器T0中断允许位;
EX1(IE.2),外部中断0允许位;
ET1(IE.3),定时/计数器T1中断允许位;
ES(IE.4),串行口中断允许位;
EA (IE.7), CPU中断允许(总允许)位。

IP

PX0(IP.0),外部中断0优先级设定位;
PT0(IP.1),定时/计数器T0优先级设定位;
PX1(IP.2),外部中断0优先级设定位;
PT1(IP.3),定时/计数器T1优先级设定位;
PS (IP.4),串行口优先级设定位;
PT2 (IP.5) ,定时/计数器T2优先级设定位。

IPH

PX0(IPH.0),外部中断0优先级设定位;
PT0(IPH.1),定时/计数器T0优先级设定位;
PX1(IPH.2),外部中断0优先级设定位;
PT1(IPH.3),定时/计数器T1优先级设定位;
PS (IPH.4),串行口优先级设定位;
PT2 (IPH.5) ,定时/计数器T2优先级设定位。

工作方式寄存器TMOD

低四位用于T0,高四位用于T1
GATE:门控位。GATE=0时,只要用软件使TCON中的TR0或TR1为1,就可以启动定时/计数器工作;GATA=1时,要用软件使TR0或 TR1为1,同时外部中断引脚或也为高电平时,才能启动定时/计数器工作。即此时定时器的启动多了一条件。
C/T:定时/计数模式选择位。 =0为定时模式; =1为计数模式。
M1M0:工作方式设置位。定时/计数器有四种工作方式,由M1M0进行设置。

控制寄存器TCON

TF1(TCON.7):T1溢出中断请求标志位。T1计数溢出时由硬件自动置TF1为1。CPU响应中断后TF1由硬件自动清0。T1工作 时,CPU可随时查询TF1的状态。所以,TF1可用作查询测试的标志。TF1也可以用软件置1或清0,同硬件置1或清0的效果一样。
TR1(TCON.6):T1运行控制位。TR1置1时,T1开始工作;TR1置0时,T1停止工作。TR1由软件置1或清0。所以,用软件可控制定时/ 计数器的启动与停止。
TF0(TCON.5):T0溢出中断请求标志位,其功能与TF1类同。
TR0(TCON.4):T0运行控制位,其功能与TR1类同。

定时/计数器的工作方式0原理图

方式0为13位计数,由TL0的低5位(高3位未用)和TH0的8位组成。TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的 TF0标志,向CPU发出中断请求。

定时器模式时有:N=t/ Tcy
计数初值计算的公式为:
定时器的初值还可以采用计数个数直接取补法获得。
计数模式时,计数脉冲是T0引脚上的外部脉冲。

门控位GATE具有特殊的作用。当GATE=0时,经反相后使
或门输出为1,此时仅由TR0控制与门的开启,与门输出1
时,控制开关接通,计数开始;当GATE=1时,由外中断引脚信号控制或门的输出,此时控制与门的开启由外中断引脚信号和TR0共同控制。当TR0=1 时,外中断引脚信号引脚的高电平启动计数,外中断引脚信号引脚的低电平停止计数。这种方式常用来测量外中断引脚上正脉冲的宽度。
定时/计数器的工作方式1原理图

方式1的计数位数是16位,由TL0作为低8位、TH0作为高8位,组成了16位加1计数器 。

定时/计数器的工作方式2原理图

方式2为自动重装初值的8位计数方式。

定时/计数器的工作方式3原理图

方式3只适用于定时/计数器T0,定时器T1处于方式3时相当于TR1=0,停止计数。 工作方式3将T0分成为两个独立的8位计数器TL0和TH0 。

RS-232C标准接口主要引脚定义

RS232C电平与TTL电平转换驱动电路

80C51串行口的结构

SCON

SM2,多机通信控制位,主要用于方式2和方式3。当接收机的SM2=1时可以利用收到的RB8来控制是否激活RI(RB8=0时不激活RI,收到 的信息丢弃;RB8=1时收到的数据进入SBUF,并激活RI,进而在中断服务中将数据从SBUF读走)。当SM2=0时,不论收到的RB8为0和1,均 可以使收到的数据进入SBUF,并激活RI(即此时RB8不具有控制RI激活的功能)。通过控制SM2,可以实现多机通信。
在方式0时,SM2必须是0。在方式1时,若SM2=1,则只有接收到有效停止位时,RI才置1。

REN,允许串行接收位。由软件置REN=1,则启动串行口接收数据;若软件置REN=0,则禁止接收。

TB8,在方式2或方式3中,是发送数据的第九位,可以用软件规定其作用。可以用作数据的奇偶校验位,或在多机通信中,作为地址帧/数据帧的标志 位。
在方式0和方式1中,该位未用。

RB8,在方式2或方式3中,是接收到数据的第九位,作为奇偶校验位或地址帧/数据帧的标志位。在方式1时,若SM2=0,则RB8是接收到的停止 位。

TI,发送中断标志位。在方式0时,当串行发送第8位数据结束时,或在其它方式,串行发送停止位的开始时,由内部硬件使TI置1,向CPU发中断申 请。在中断服务程序中,必须用软件将其清0,取消此中断申请。

RI,接收中断标志位。在方式0时,当串行接收第8位数据结束时,或在其它方式,串行接收停止位的中间时,由内部硬件使RI置1,向CPU发中断申 请。也必须在中断服务程序中,用软件将其清0,取消此中断申请。

PCON

SMOD(PCON.7) 波特率倍增位。在串行口方式1、方式2、方式3时,波特率与SMOD有关,当SMOD=1时,波特率提高一倍。复位时,SMOD=0。

串口方式0的输出

串口方式0的输入

串口方式0的电路图

串口方式1数据格式

串口方式1的输出

串口方式1的输入

用软件置REN为1时,接收器以所选择波特率的16倍速率采样RXD引脚电平,检测到RXD引脚输入电平发生负跳变时,则说明起始位有效,将其移入 输入移位寄存器,并开始接收这一帧信息的其余位。接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移 位。当RI=0,且SM2=0(或接收到的停止位为1)时,将接收到的9位数据的前8位数据装入接收SBUF,第9位(停止位)进入RB8,并置 RI=1,向CPU请求中断。

串口方式2和3数据格式

方式2或方式3时为11位数据的异步通信口。TXD为数据发送引脚,RXD为数据接收引脚 。
方式2和方式3时起始位1位,数据9位(含1位附加的第9位,发送时为SCON中的TB8,接收时为RB8),停止位1位,一帧数据为11位。方式2的波 特率固定为晶振频率的1/64或1/32,方式3的波特率由定时器T1的溢出率决定。

串口方式2和3的输出

发送开始时,先把起始位0输出到TXD引脚,然后发送移位寄存器的输出位(D0)到TXD引脚。每一个移位脉冲都使输出移位寄存器的各位右移一位, 并由TXD引脚输出。
第一次移位时,停止位“1”移入输出移位寄存器的第9位上 ,以后每次移位,左边都移入0。当停止位移至输出位时,左边其余位全为0,检测电路检测到这一条件时,使控制电路进行最后一次移位,并置TI=1,向 CPU请求中断。

串口方式2和3的输入

接收时,数据从右边移入输入移位寄存器,在起始位0移到最左边时,控制电路进行最后一次移位。当RI=0,且SM2=0(或接收到的第9位数据为 1)时,接收到的数据装入接收缓冲器SBUF和RB8(接收数据的第9位),置RI=1,向CPU请求中断。如果条件不满足,则数据丢失,且不置位RI, 继续搜索RXD引脚的负跳变。

波特率的计算

方式0的波特率 = fosc/12
方式2的波特率 =(2SMOD/64)· fosc
方式1的波特率 =(2SMOD/32)·(T1溢出率)
方式3的波特率 =(2SMOD/32)·(T1溢出率)
T1 溢出率 = fosc /{12×[256 -(TH1)]}

串口初始化步骤

确定T1的工作方式(编程TMOD寄存器);
计算T1的初值,装载TH1、TL1;
启动T1(编程TCON中的TR1位);
确定串行口控制(编程SCON寄存器);
串行口在中断方式工作时,要进行中断设置(编程IE、IP寄存器)。

单片机与单片机通信电路图

25May/10

AT89S52 中断优先级设置

Posted by Nick Xu

void Openint(void)   //打开中断
{
EA=1;//开中断
IT0=1; //外部中断0下降沿触发
IT1=1; //外部中断1下降沿触发
EX0=1;//外部中断0
EX1=1;//外部中断1
ET0=1;//开timer0中断
ES=0;//开串口中断

}

void IntGradeSet(void)  //设置优先级
{
PS=0;      //串口优先级
PT0=0;  //timer0中断优先级
PT1=0;  //timer1中断优先级
PX0=0;  //int0中断优先级
PX1=0;  //int1中断优先级
}

void UARTint(void) interrupt 4   using 3        //串口中断处理
{
uchar     receivr_buffer;
TI=0; //很重要,否则会一直进中断处理程序的!
EA=0;
if(RI==1)
{
RI=0;
receivr_buffer = SBUF;

if (point == 0)
{
if (receivr_buffer == 0xa5)
IDChageRx[point++] = receivr_buffer;
//point++;
else point = 0;
}

else if (point>0 && point<4)
IDChageRx[point++] = receivr_buffer;

else
{
point = 0;
IDChageRx[0]=0;
IDChageRx[1]=0;
IDChageRx[2]=0;
IDChageRx[3]=0;
}
}
EA=1;
}

我现在在开发一个系统,用了三个中断,有外部中断1,定时器中断0,串口中断,我设定 中断的优先级是:定时器中断,串口中断,外部中断,而且我的三个中断经常发生,有可能出现中断三级嵌套,也就是说,正在进行外部中断1,串口中断来了,在 进行串口中断的同时,这时定时器中断来了。这样系统运行可靠吗?
=============================
我也曾做过一个三级嵌套程序。只不过我是用到两个定时中断和串口中断,正常的中断优先级 为:INT0>T0>INT1>T0>串口中断。
51系列只两个中断优先级。设置时应该保证:高优先级中断和低优先级中断中的若干中断仍要满足上头提到的正常情况下的优先级。如:
要实现:INT1>T0>串口中断,则应该设置如下
SETB PX1
CLR PX0
CLR PT0
CLR PT1
CLR PS(串口中断优先级设置)
你的意思应该是要实现:T0>串口中断>INT0
则设置如下:
SETB PT0
SETB PS
CLR PX0
CLR PX1
CLR PT1
运行可靠。

22May/10

STM32 入门教程 基于 MDK 的 SWD 两线串行仿真

Posted by Nick Xu

(1) SWD 仿真模式概念简述
先所说 SWD 和传统的调试方式有什么不一样:

首先给大家介绍下经验之谈:
(一): SWD 模式比 JTAG 在高速模式下面更加可靠. 在大数据量的情况下面 JTAG 下载程序会 失败, 但是 SWD 发生的几率会小很多. 基本使用 JTAG 仿真模式的情况下是可以直接使用 SWD 模式的, 只要你的仿真器支 持. 所以推荐大家使用这个模式.
(二): 在大家 GPIO 刚好缺一个的时候, 可以使用 SWD 仿真, 这种模式支持更少的引脚.
(三): 在大家板子的体积有限的时候推荐使用 SWD 模式, 他需要的引脚少, 当然需要的 PCB 空间就小啦. 比如: 你可以选择一个很小的 2.54 间距的 5 芯端子做仿真接口.

(2) 仿真器对 SWD 模式支持情况
再说说市面上的常用仿真器对 SWD 仿真的支持情况.

(1)  JLINKV6 支持 SWD 仿真模式. 速度较慢.
(2)  JLINKV7 比较好的支持 SWD 仿真模式, 速度有了明显的提高. 速度是 JLINKV6 的 6 倍.
(3)  JLINKV8 非常好的支持 SWD 仿真模式, 速度可以到 10M.
(4)  ULINK1  不支持 SWD 模式
(5)  盗版 ULINK2  非常好的支持 SWD 模式. 速度可以达到 10M.
(6)  正版 ULINK2  非常好的支持 SWD 模式. 速度可以达到 10M.

再所说硬件上的不同:
(1)  JLINKV6 需要的硬件接口为: GND, RST, SWDIO, SWDCLK
(2)  JLINKV7 需要的硬件接口为: GND, RST, SWDIO, SWDCLK
(3)  JLINKV8 需要的硬件接口为: VCC, GND, RST, SWDIO, SWDCLK
(4)  ULINK1  不支持 SWD 模式
(5)  盗版 ULINK2  需要的硬件接口为: GND, RST, SWDIO, SWDCLK
(6)  正版 ULINK2  需要的硬件接口为: GND, RST, SWDIO, SWDCLK
由此可以看到只有 JLINKV8 需要 5 个引脚. 那么给大家介绍下为什么有了 VCC 这个引脚时候有好处, 我的个人理解: 我认为有这个引脚是最合适的, 仿真器对目标板子的仿真需要用到 RST 引脚, 其实使用仿真器内部的 VCC 做这个功能其实并不是非常美妙. 因此 JLINKV8 选择了只和目标板共 GND, 但是不共 VCC. 因此我觉得这种模式最合理, 当然通常情况下仿真器和目标板共 GND 和 VCC 是没有错的.

下面两张演示就是我使用 JLINKV8 进行下载程序到 Mini-STM32 开发板上仿真的图片. 程序代码中使用 了 uCGUI , 一共程序代码 120K 左右. 使用 JLINKV8 下载到芯片中只需要 5 秒左右.

SWD1.jpg

下 载 (61.11 KB)

2009-9-5 20:32

SWD2.jpg

下 载 (62.06 KB)

2009-9-5 20:32

SWD3.jpg

下 载 (49.7 KB)

2009-9-5 20:32

(3) 在 MDK 中SWD 模式设置

接下来告诉大家怎么使用 SWD 设置:

打开工程 Option 设置:

SWD4.jpg

下 载 (54.8 KB)

2009-9-5 21:16

SWD5.jpg

下 载 (64.5 KB)

2009-9-5 21:16

在设置中按照上图设置成 SWD 模式, 速度你可以按照你的实际需求来设置, 如果你的板子供电系统不是特别稳定, 纹波比较大或者仿真线比较长可以设置成 500K 或者 1M , 如果环境很好当然可以选择 10M , 当然速度会飞起来.

记得不要忽略了左下方的那个

USB

还是 TCP 模式, 当然我们是 USB 模式, 因为有的时候默认是 TCP 模式, 这个时候我们忽略这个设置后会仿真常常连接不上的.

注意: 上面这个界面是在仿真器插在电脑上才会出现的界面, 就是说没有实际插入仿真器的话不会出现这个界面的.
当然虽然上面是 JLINKV8, ULINK2 下的设置也是一样的.

22May/10

STM32 入门教程 RTC 实时时钟

Posted by Nick Xu

(一) STM32 RTC 实时时钟概要
STM32内部RTC功能非常实用,它的供电和时钟是独立于内核的,可以说是STM32内部独立的外设模块,有加上RTC内部寄存器不受系统复位掉电的影 响,我们可以才用外部电池供电和32768表振晶体来实现真正RTC(实时时钟)功能。

这里引用手册里一段概述:

RTC由两个主要部分组成。第一部分(APB1接口)用来和 APB1总线相连。此单元还包含一组 16位寄存器,可通过 APB1总线对其进行读写操作。APB1接口以 APB1总线时钟为时钟,用来与 APB1总线接口。

另一部分(RTC核)由一系列可编程计数器组成,分成两个主要模块。第一个模块是 RTC的预分频模块,它可编程产生最长为 1秒的 RTC时间基准 TR_CLK。RTC的预分频模块包含了一个 20位的可编程分频器(RTC预分频器)。在每个TR_CLK周期中,如果在 RTC_CR 寄存器中设置了相应允许位,则 RTC产生一个中断(秒中断)。第 2个模块是一个 32位的可编程的计数器,它可被初始化为当前的系统时间。系统时间以 TR_CLK速度增长并与存储在 RTC_ALR寄存器中的可编程的时间相比较,如果 RTC_CR控制寄存器中设置了相应允许位,则比较匹配时将产生一个闹钟中断。

3.jpg

下载 (66.99 KB)

2009-8-24 21:46

2.jpg

下载 (67.56 KB)

2009-8-24 21:44

(二) 程序编写

(1) 系统启动后检查RTC是否已设置。由于RTC在BKP区域,当Vdd掉电之后可由后备电源提供电源,当后备电源连接到针脚VBAT上时,RTC的设置不会 由于外部电源的断开而丢失。在本例中写一个值到BKP_DR1中以标示RTC是否已配置,在启动之后程序检查BKP_DR1的值。

(2)  若BKP_DR1的值不正确:(BKP_DR1的值有误或者由于是第一次运行值还未写进去),则需要配置时间并且询问用户调整时间。

(3) 若BKP_DR1的值正确,则意味着RTC已配置,此时将在超级终端上显示时间。

(4) 整个工程包含3个源文件:STM32F10x.s、stm32f10x_it.c和main.c,其中STM32F10x.s为启动

代码

,所有中断服务子程序均在stm32f10x_it.c中,其它函数则在main.c中。下面分别介绍相关的函数,具体程序清单见参考程序。

函数RTC_IRQHandler用于处理秒中断事件,在每次遇到23:59:59时将时钟回零。

函数RTC_Configuration用于配置RTC模块。

函数USART_Scanf用于从PC超级终端中获取数字值,Time_Regulate利用函数USART_Scanf从超级终端获取新的RTC 时间 值,函数Time_Adjust则利用函数USART_Scanf设置新的RTC时间。函数Time_Display和Time_Show用于将RTC时 间转换了字符串送往USART1。

源文件其他函数,例如

GPIO

、RCC、NVIC、USART的配置,在此不作冗述。

(三) 仿真调试

(1) 使用Keil uVision3 通过ULINK 2

仿真器

连接实验板,打开实验例程目录Example10-RTC子目录下的RTC.Uv2例程,编译

链接

工程;

(2) 使用STM32开发板附带的串口线,连接开发板上的COM0和PC机的串口;

(3) 在PC机上运行Windows自带的超级终端串口通信程序(波特率115200、1位停止位、无校验位、无硬件流控制);或者使用其它串口通信程序;

(4) 选择硬件调试模式,点击

MDK

的Debug菜单,选择Start/Stop Debug Session项或Ctrl+F5键,远程连接目标板并下载调试代码到目标系统中;

(5) 例程正常运行之后会在超级终端显示以下信息:

麦思网原创

教程
www.mystm32.com/bbs

MINI-STM32  STM32F103RBT6 RTC

RTC not yet configured....

RTC configured....

============TimeSettings===================

Please Set Hours:

在PC机上依次输入时钟、分钟、秒钟之后每隔1秒在超级终端上显示一次时间:

Please Set Hours:  12

Please Set Minutes:  0

Please Set Seconds:  0

Time: 12:00:00

(6) 程序正常运行并在开发外部电源保持的情况下,按下Reset

按钮

,PC超级终端上将继续显示正常时间:

External Reset occurred....

No need to configure RTC....

Time: 12:03:09

(7) 程序正常运行时断开开发板外部电源,然后重新接上外部电源,PC超级终端上也将继续显示正常时间:

Power On Reset occurred....

No need to configure RTC....

Time: 12:05:57

(8) 取下处理器板上的纽扣电池,并断开外部电源,然后重新接上外部电源,PC超级终端上将无法继续正常显示时间,PC超级终端将出现第(5)步所出现内容。

(9) 也可采用

软件

调试模式,利用USART窗口来

模拟

实现COM0的输入和输出。

请参考下图: 你需要在超级终端中敲击按键来设置时钟.

1.jpg

下载 (45.33 KB)

2009-8-24 21:17
22May/10

STM32 入门教程 内部温度传感器

Posted by Nick Xu

(一) STM32 内部温度传感器概要

STM32 芯片内部一项独特的功能就是内部集成了一个温度传感器, 因为是内置, 所以测试的是芯片内部的温度, 如果芯片外接负载一定的情况下, 那么芯片的发热也基本稳定, 相对于外界的温度而言, 这个偏差值也是基本稳定的. 也就是说用 STM32 内部传感器来测量外界环境的温度.

在一些恶劣的应用环境下面, 可以通过检测芯片内部而感知设备的工作环境温度, 如果温度过高或者过低了 则马上睡眠或者停止运转. 可以保证您的设备工作的可靠性.

1.  STM32内部温度传感器与ADC的通道16相连,与ADC配合使用实现温度测量;
2.  测量范围–40~125℃,精度±1.5℃。
3.  温度传感器产生一个随温度线性变化的电压,转换范围在2V < VDDA < 3.6V之间。

转换公式如下图所示:

1.jpg

下载 (64.9 KB)

2009-8-23 21:50

手册中对于公式中的参数说明:

2.jpg

下载 (48.4 KB)

2009-8-23 21:24

(二) 程序编写

代码

的时候, 在测量要求不怎么高的情况下, 公式可以简化.

简化的公式:

Temperature= (1.42 - ADC_Value*3.3/4096)*1000/4.35 + 25;

程序编写:

1. 初始化ADC , 初始化

DMA

可以参考贴子:

[原创] MINI-STM32 开发板

入门教程

(六) 基于 DMA 的 ADC
http://www.mystm32.com/bbs/viewthread.php?tid=42&extra=page%3D1

主意:  内部温度传感器是使用了 ADC1 的第 16 通道哦.

2.  ADC_TempSensorVrefintCmd(ENABLE);

使能温度传感器和内部参考电压通道

3. 按照刚才列出的公式计算

Temperature= (1.42 - ADC_Value*3.3/4096)*1000/4.35 + 25;

第二步是做什么的呢?  参考下图:

3.jpg

下载 (20.42 KB)

2009-8-23 21:50

(三) 仿真调试

(1) 使用Keil uVision3 通过ULINK 2

仿真器

连接实验板,使用MINI-STM32 开发板附带的串口线,连接实验板上的 UART1 和 PC 机的串口,打开实验例程目录下的ADC.Uv2例程,编译

链接

工程;

(2) 在 PC 机上运行 windows 自带的超级终端串口通信程序(波特率115200、1位停止位、无校验位、无硬件流控制);或者使用其它串口通信程序;

(3) 点击

MDK

的Debug菜单,点击Start/Stop Debug Session;

(4) 全速运行程序, 显示结果如下所示。

麦思网原创教程
www.mystm32.com/bbs

1.jpg

下载 (54.75 KB)

2009-8-23 22:53
22May/10

STM32 入门教程 Unique Device ID

Posted by Nick Xu

每一片 STM32 芯片内部拥有一个独一无二的 Unique Device ID, 96 Bit.

这个 ID 号可以提供给开发者很多优越的功能, 例如:
1. 可以把 ID 做为用户最终产品的序列号,帮助用户进行产品的管理。
2. 在某些需要保证安全性的功能代码运行前,通过校验此 ID,保证最终产品的某些功能的安全性。
3. 用 ID 配合加解密算法,对芯片内部的代码进行加加密,以保证用户产品的安全性和不可复制性。

这项功能相信对那些不希望自己的产品不被别人抄袭来说肯定是个非常不错的。

下面我就先大家介绍如何读出这个 ID:

这个 ID 号是放在片内 Flash 中的固定的位置,直接读取出来就行了. 96 位的独特 ID 位于地址 0x1FFFF7E8 ~ 0x1FFFF7F4 的系统存储区, 由 ST 公司在工厂中写入 (用户不能修改) 用户可以以字节、半字、或字的方式单独读取其间的任一地址.

(一) 配置好串口, 用于调试演示, 这一部份前面的章节我们已经介绍过了.
可以参考贴子:
[原创] MINI-STM32 开发板入门教程 (六) 基于 DMA 的 ADC
http://www.mystm32.com/bbs/viewthread.php?tid=42&extra=page%3D1

当然也可以直接下载我们的例程去读这部分的程序.

(二) 读取 Unique Device ID

u32 Dev_Serial0, Dev_Serial1, Dev_Serial2;

Dev_Serial0 = *(vu32*)(0x1FFFF7E8);
Dev_Serial1 = *(vu32*)(0x1FFFF7EC);
Dev_Serial2 = *(vu32*)(0x1FFFF7F0);

(三) 仿真调试

(1) 使用Keil uVision3 通过ULINK 2仿真器连接实验板,使用MINI-STM32 开发板附带的串口线,连接实验板上的 UART1 和 PC 机的串口,打开实验例程目录下的ADC.Uv2例程,编译链接工程;
(2) 在 PC 机上运行 windows 自带的超级终端串口通信程序(波特率115200、1位停止位、无校验位、无硬件流控制);或者使用其它串口通信程序;
(3) 点击MDK 的Debug菜单,点击Start/Stop Debug Session;
(4) 全速运行程序, 显示结果如下所示。

麦思网原创教程
www.mystm32.com/bbs
MINI-STM32  STM32F103RBT6 Unique Device ID:
066C0033 32353958 43195835

备注: 其中最后一行的数字就是我的 MINI-STM32 开发板中 STM32F103RBT6 的 Unique Device ID. 您的 ID 当然肯定会和我的不一样哦.

1.jpg

下载 (69.73 KB)

2009-8-23 20:16
22May/10

STM32 入门教程 工业现场总线 CAN

Posted by Nick Xu

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

首先通读手册中关于CAN的文档,必须精读。
STM32F10xxx 参考手册Rev7V3.pdf
http://www.mystm32.com/bbs/redirect.php?tid=255&goto=lastpost#lastpost

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

关于 STM32 的 can 总线简单介绍
bxCAN 是基本扩展 CAN (Basic Extended CAN) 的缩写,它支持 CAN 协议 2.0A 和 2.0B 。它的设计目标是,以最小的 CPU 负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性可软件配置)。
对于安全紧要的应用,bxCAN 提供所有支持时间触发通信模式所需的硬件功能。

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

发送
· 3 个发送邮箱
· 发送报文的优先级特性可软件配置
· 记录发送 SOF 时刻的时间戳

接收
· 3 级深度的2个接收 FIFO
· 14 个位宽可变的过滤器组 - 由整个 CAN 共享
· 标识符列表
· FIFO 溢出处理方式可配置
· 记录接收 SOF 时刻的时间戳

可支持时间触发通信模式
· 禁止自动重传模式
· 16 位自由运行定时器
· 定时器分辨率可配置
· 可在最后 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_LoopBackCAN_Mode_Normal 两种模式。
我们第一步做的就是使用运行在 CAN_Mode_LoopBack 下进行自测试。

在参考手册中 CAN_Mode_LoopBack (环回模式) 的定义如下:
环回模式可用于自测试。为了避免外部的影响,在环回模式下 CAN 内核忽略确认错误 (在数据 / 远程帧的确认位时刻,不检测是否有显性位) 。在环回模式下,bxCAN 在内部把 Tx 输出回馈到 Rx 输入上,而完全忽略 CANRX 引脚的实际状态。发送的报文可以在 CANTX 引脚上检测到。
因此这种模式也特别适合大家做好硬件后自测程序。

2.jpg

下载 (37.38 KB)

2009-8-16 11:46

(三) CAN 接口端口映射

STM32 中的 CAN 物理引脚脚位可以设置成三种:

默认模式,重定义地址1模式,重定义地址2模式

2.jpg

下载 (28.94 KB)

2009-8-16 11:51

在我们的 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);

/* 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  重影射 */

//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)

// 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。

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

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

/* 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 软件仿真模拟器

调用出来.

4.JPG

下载 (61.84 KB)

2009-8-16 00:27

大家可以仿真程序,当程序中 Test 等于 Passed 那么说明 Loopback 模式测试通过了。

并且在 CAN 通讯框中我们可以看到发送和接收到的数据:

5.jpg

下载 (51.48 KB)

2009-8-16 12:27

回循模式下的源代码, 基于 MDK3.5:
Example7.1-CAN LoopBack Mode.rar

(493.79 KB)

下载次数: 83
阅读权限: 10

2009-8-16 12:35

到此时说明如果大家只有一块CAN模块的时候学习可以告一个段落了,不过这个并不代表大家就已经掌握了 CAN 了,正真要掌握它,大家还是需要看大量的 CAN 部分的资料,参考手册部分的也是不够的,市面上有几本专门介绍现场总线和CAN总线的书,推荐大家买来经常翻翻看看,这样到需要实际应用的时候才可以做到 如鱼得水。

(五) 正常模式

完成了 loopback 模式的测试之后接下来我们需要学习的就是多机通讯了,当然由于我们的 Mini-STM32 没有将 CAN 接口引出来, 所以我们没有办法在板子上面做这部分的试验了,只能在 RealView MDK 的软件中进行模拟。

如果您拥有两块带 CAN 硬件的 STM32 的板子,您需要自己构建硬件的物理层的连接, 使用三根线将 CANH,CANL,GND 三根线直连,当然你要接好终端电阻才能保证通讯的正常通讯,当两块板子都跳好后我们使用万用表测量下 CANH和CANL之间的电阻是否为 60 欧姆。多块板子多机通讯的是否你只需要在总线的主机端和最后一端接上终端电阻就可以了.

3.jpg

下载 (24.18 KB)

2009-8-15 23:11

在初始化完成后,软件应该让硬件进入正常模式,以便正常接收和发送报文。软件可以通过对 CAN_MCR 寄存器的INRQ位清 '0',来请求从初始化模式进入正常模式,然后要等待硬件对 CAN_MSR 寄存器的 INAK 位置 '1' 的确认。在跟 CAN 总线取得同步,即在 CANRX 引脚上监测到 11 个连续的隐性位 (等效于总线空闲) 后,bxCAN 才能正常接收和发送报文。

不需要在初始化模式下进行过滤器初值的设置,但必须在它处在非激活状态下完成 (相应的 FACT 位为 '0' ) 。而过滤器的位宽和模式的设置,则必须在初始化模式中进入正常模式前完成。

准备工作做完我们需要设置 CAN 通讯部份软件。

我们把 TestStatus CAN_Polling(void) 函数和 TestStatus CAN_Interrupt(void) 函数中的 LoopBack 模式修改为 Normal 模式.

//CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack;

CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;

接下来我们就可以做实验了. 但是由于 RealView MDK 的 CAN 模块没有办法接收, 所以我们只做发送的例子.

我们的例子中分别发送两帧数据:
(1) TestStatus CAN_Polling(void) 查询发送

第一帧数据为:  ID 为 0x11, 数据为 8 个字节的一个数据包.

TxMessage.StdId=0x11;

TxMessage.RTR=CAN_RTR_DATA;

TxMessage.IDE=CAN_ID_STD;

TxMessage.DLC=8;

TxMessage.Data[0]=0x01;

TxMessage.Data[1]=0x02;

TxMessage.Data[2]=0x03;

TxMessage.Data[3]=0x04;

TxMessage.Data[4]=0x05;

TxMessage.Data[5]=0x06;

TxMessage.Data[6]=0x07;

TxMessage.Data[7]=0x08;

(2) TestStatus CAN_Interrupt(void) 中断发送

第二帧数据为:ID 为 0x1234, 数据为 8 个字节的一个数据包.

TxMessage.StdId=0x12;

TxMessage.ExtId=0x34;

TxMessage.IDE=CAN_ID_EXT;

TxMessage.RTR=CAN_RTR_DATA;

TxMessage.DLC=8;

TxMessage.Data[0]=0x11;

TxMessage.Data[1]=0x22;

TxMessage.Data[2]=0x33;

TxMessage.Data[3]=0x44;

TxMessage.Data[4]=0x55;

TxMessage.Data[5]=0x66;

TxMessage.Data[6]=0x77;

TxMessage.Data[7]=0x88;

CAN_Transmit(&TxMessage);

在主函数中初始化之后加上这两句发送函数:

/* CAN transmit at 100Kb/s and receive by polling in Normal mode*/

CAN_Polling();

while(i++ < 1000);

/* CAN transmit at 500Kb/s and receive by interrupt in Normal mode*/

CAN_Interrupt();

程序改完了, 我们需要编译通过后, 点软件仿真.

CAN 软件仿真模拟器

调用出来.

接下来我们全速运行到 while(1) 就可以看到结果了.

1.jpg

下载 (87.37 KB)

2009-8-16 00:24
22May/10

STM32 入门教程 基于 DMA 的 ADC

Posted by Nick Xu

(一) STM32 ADC 模块介绍

2.jpg

下载 (52.26 KB)

2009-8-21 23:41

1.jpg

下载 (69.24 KB)

2009-8-21 23:41

(二) 程序编写
(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; //内存数据字长
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));

/* 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

The current AD value = 0x0ACA

The current AD value = 0x0B0D

The current AD value = 0x0B10

The current AD value = 0x0B0E

....

....

(5) 若无开发板,读者也可以使用

软件

仿真模式来完成程序运行。

1.jpg

(77.9 KB)

2009-8-21 23:54
site
site