历史上的今天
返回首页

历史上的今天

今天是:2024年11月19日(星期二)

正在发生

2018年11月19日 | 真干货!从51到stm32开发入门

2018-11-19 来源:eefocus

 本来只是路过,写详细一点。


我看楼主浮躁得不得了。现在什么都不要做了,先去看几遍《不要做浮躁的嵌入式工程师》这篇文章,想清楚了,


再动手吧。


我做了个实例,不用ST的库来点LED,解答你的问题


我的 KeilMDK 3.5


我的STM32板子奋斗版是 ,IC 是 STM32F103VET6


调试工具 JLINK V8


LED 接在 PB5 ,高电平点亮


既然楼主说一定懂C语言了,那么对于下面我的问题,不查百度,完全靠自己,懂多少?然后查了百度之后又能懂多少?


(一)新建 keil 工程,IC选择 ST 公司的 STM32F103VE,keil提示是否copy 启动文件,选择是。


这里有问题问楼主,


你有没有读过这个启动头文件? 51 也是同样的启动文件,51的那个启动文件有没有读过?你知道


头文件里面做了什么吗? C语言真的从 main 函数开始吗?运行时库是什么?这些资料从


什么地方知道?keil编译器的行为?


(如果你说头文件是汇编的,没有必要看,那我当我没说)


例如启动文件里面有这么一句,我的问题是 __main 这个标号在哪里实现的,注意,这里肯定不是 main 函数


这里跳到哪里去了?还有个问题 [WEAK] 这里是什么意思?有什么用????


Reset_Handler PROC


EXPORT Reset_Handler [WEAK]


IMPORT __main


LDR R0, =__main


BX R0


(二)新建一个 main.c 并且写一个 main函数,什么都不做,这和51一样了。


void main(void)


{


while (1)


{


}


}


然后因为我需要调试,则设置jlink调试器,在项目属性里面 Debug 标签,Use J-LINK/J-TRACE ,然后到utilities 标签,同样选择J-LINK /J-TRACK ,并且选择 Setting 按钮,里面的 Programming Algorithm还是空的,表示keil 不知道目标是什么,我添加一个 STM32F10X High-density Flash ,问题,为什么是High-desity ?依据是什么???


全部确认返回。


这个时候已经可以编译,开发板上电,已经可以下载仿真的,虽然程序什么都没有写


(三)既然硬件,仿真器,调试都准备好了,接着就开始写程序了。


我一直推荐新手花钱买学习板和仿真器,因为可以排除硬件的问题,让初学者集中精力去写程序,而不用怀疑


硬件有问题,这点很重要。


这阶段主要是看书,了解这个IC 的架构,了解指令集,了解寄存器(别跟我说你找不到这些资料? .....)


Cortex-M3权威指南CnR2(电子书).pdf


STM3210x参考手册.pdf


学习板原理图


博客,论坛等多个帖子,务必要对整个IC有个初步的了解。这个过程有点痛苦,但是值得花这个时间。


(四)开始写 LED


既然我们要操作 IO 口,当然就要看IO口相关的知识。打开 STM3210x参考手册.pdf ,我的目的只是操作 GPIO


所以我只需要将第五章看完就OK了。章节比较多,懒得看,根据一般的经验(楼主,你缺经验了吧?),不说多


就AVR 和 PIC 而已。操作IO一般是两个步骤,第一,操作IO控制寄存器,设置IO为输出,第二就是送数据。


那么很明显,只可能是 GPIOx_CRL GPIOx_CRH , GPIOx_ODR 三个寄存器会有想要


仔细阅读这几个寄存器的介绍后知道,GPIOx_CRL 是控制 PIN 0-7 的属性的,GPIOx_CRH 控制PIN 8-15,ODR寄存器


当然就是输出数据了,将数据送到这里就行了。


然后,这几个寄存器的地址是多少?首先看 stm32f103ve.pdf 这个是官方的datasheet、,看第四章, Mmeory Mapping


为什么看这章?会英文都能猜到吧?,看 PORTB 的地址是 0x40010C00 - 0x40010FFF ,这个就是基地址了。基地址


加上偏移量就能找到具体的寄存器。


例如我需要操作 GPIOB_CRL 的偏移为 00H ,(看STM3210x参考手册.pdf) ODR 寄存器的偏移为 0CH


那么很自然得出


GPIOB_CRL = 0x40010C00


GPIOB_ODR = 0x40010C0C


怎么验证我的结论正确?先看 keil 给的头文件 \Keil\ARM\INC\ST\STM32F10x\stm32f10x_map.h


#define PERIPH_BASE ((u32)0x40000000)


#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)


#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)


这样怎么算都能算出 0x40010C00 出来吧??ODR 寄存器同理


为了点亮 LED ,我需要将 PB5 (也就是 GPIOB5)设置为输出,并且ODR相应的位写入 1 ,看资料得出 MODE5 是bit 20 21 控制的,CNF5 是bit 22,23


MODE5应该设置 10(0x2) 选择 2MHZ 输出,CNF5 选择00(0x0),通用推挽模式,于是将这个值写入

(*volatile unsigned long)0x40010C00 = (2<<20) | (0<<22); // 为简单起见,不管其他位了


楼主你是否能看懂这句C语言??volatile 什么意思什么用?指针的本质是什么?为什么能这样用?2<<20 是什么


意思,为什么能这样用?楼主我真的不是为难你,嵌入式都这么写的,ST的头文件也是这么定义


同理,设置 ODR 寄存器


*(volatile unsigned long *)0x40010C0C = 1<<5;


*(volatile unsigned long *)0x40010C0C = 0;


STM32 没有SFR ,没有bit,没有sbit 的概念的了。是不是就不如 51 了?


下载运行,还不行,因为GPIOB 的CLK 没有使能,这时其实 GPIOB 是不能工作的,这是 STM32 特殊的地方,上电默认外设的时钟都是关的,初学者没有注意这里,是可以原谅的,多看看书,多实践,多问问就是了。


找到问题的原因,则再 RCC_APB2ENR 设置,其中 BIT 3 就是 IOPBEN 是时钟使能位,同上,先找到 RCC_APB2ENR的地址


#define PERIPH_BASE ((u32)0x40000000)


#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)


#define RCC_BASE (AHBPERIPH_BASE + 0x1000)


RCC_APB2ENR 的偏移是 18H ,所以最终得到地址为 0x40021018,操作方法同上


*(volatile unsigned long *)0x40021018 |= 1<<3;


最终的点LED的程序就完成了。


void main(void)


{


*(volatile unsigned long *)0x40021018 |= 1<<3;


*(volatile unsigned long *)0x40010C00 = (2<<20) | (0<<22);


*(volatile unsigned long *)0x40010C0C = 1<<5;


while (1)


{


}


}


如果将寄存器做一个定义,则程序变成如下


#define RCC_APB2ENR *(volatile unsigned long *)0x40021018


#define GPIOB_CRL *(volatile unsigned long *)0x40010C00


#define GPIOB_ODR *(volatile unsigned long *)0x40010C0C


void main(void)


{


RCC_APB2ENR |= 1<<3;


GPIOB_CRL = (2<<20) | (0<<22);


GPIOB_ODR = 1<<5;


while (1)


{


}


}


RCC_APB2ENR RCC 是时钟寄存器 , APB2 是外设2 ,ENR ,可以理解为 enable


GPIOB_CRL GPIO B control 控制寄存器


GPIOB_ODR GPIO(general purpose input output) B output data register 输出数据寄存器


都是有意义的名字,哪里难记了??而且名字都来自 ST 的官方 datasheet、这个程序跟你用 51 写的程序我还真的


没看出差别有很大 .....


加入刚才的 GPIOB 寄存器,看看 ST 的官方库是怎么定义的,


\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\stm32f10x.h


用 UltraEdit 打开,搜索 GPIOB


#define PERIPH_BASE ((uint32_t)0x40000000)


#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)


#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)


没错,和keil 里面是一模一样的。


typedef struct


{


__IO uint32_t CRL;


__IO uint32_t CRH;


__IO uint32_t IDR;


__IO uint32_t ODR;


__IO uint32_t BSRR;


__IO uint32_t BRR;


__IO uint32_t LCKR;


} GPIO_TypeDef;


其中 __IO 的定义在 \Libraries\CMSIS\CM3\CoreSupport\core_cm3.h 为什么我知道在这个文件里面,因为我会


用 source insight ...


#define __IO volatile


__IO uint32_t CRL 其实就是 volatile uint32_t CRL


为什么用结构体?因为结构体的成员的地址分配(RAM中)是连续(不知道楼主是否懂得,这还是C语言的问题),


而 STM32 的一个模块的功能寄存器都是连续的,每个寄存器都是相当于 基地址加偏移,跟上面的理论一致


于是就有了结构体指针的用法


跟踪库函数的源代码,例如 GPIO 的 初始化函数


void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)


以结构体指针的形式传递 IO 口 GPIO_TypeDef* GPIOx


访问 CRL 寄存器则用成员的形式 GPIOx->CRL;


不需要担心这样做的效率,因为都是地址,也就是指针,最终的效率是直接寄存器操作,效率是非常高的。


看不懂库函数,归根究底就是C语言功底不行。不要以为写过几行51就懂C语言了,远的很呢。


还有,STM 的库下载的时候包含了很多很多例子,库函数怎么使用在例子里面有很详细的介绍,不用写几行代码,


都是复制例子做实验,也很很容易的。


总结楼主的几个问题


1,ARM 没有SFR,也不需要,SFR 是51的关键字,没有理由 51 有 ARM 就要有。例如ACC,ARM 就没有,但是有R0-R15 ,这些就是架构(architecture 的区别了)


2,STM32 的寄存器在官方头文件上面已经全部有定义了,上面已经阐述了。(你看不懂不代表没有吧?)


3,不带库函数的LED程序已经实现了。


想进步唯一的办法是多看书,多看代码,多写,多思考,少说话,楼主太浮躁了,反省一下吧。


推荐阅读

史海拾趣

Densei-Lambda (TDK)公司的发展小趣事

以下是关于Densei-Lambda(现更名为TDK-Lambda)公司在电子行业发展的五个相关故事,每个故事都尽可能客观地描述了事实,没有加入主观评价:

  1. 日本电子存储器工业株式会社的起步

TDK-Lambda的前身可以追溯到1970年成立的日本电子存储器工业株式会社。当时,该公司主要致力于电子存储器的研发和生产。在创始人及团队的共同努力下,公司逐渐在电子存储领域取得了一席之地,为后续的发展奠定了坚实的基础。

  1. 电盛兰达株式会社的成立与成长

随着时间的推移,日本电子存储器工业株式会社逐渐将业务重心转向电源领域,并于1990年代更名为电盛兰达株式会社。在电源领域,电盛兰达凭借其出色的技术实力和产品品质,迅速获得了市场的认可。同时,公司不断扩大生产规模,提高生产效率,逐渐在电源市场上占据了一席之地。

  1. TDK集团的收购与融合

2005年,TDK集团宣布收购英国Invensys旗下的Lambda集团,包括Lambda USA、Lambda Europe以及电盛兰达株式会社。这一收购不仅扩大了TDK集团的业务范围,也进一步巩固了其在电源领域的领先地位。随后,TDK集团和电盛兰达宣布将双方的电源产品统一为TDK-Lambda品牌,共同进行推广和销售。

  1. 无锡东电化兰达电子有限公司的成立与发展

1995年,电盛兰达株式会社在中国投资设立了全资子公司——无锡东电化兰达电子有限公司。该公司位于无锡新加坡工业园,专注于开关稳压电源的开发、生产和销售。多年来,无锡东电化兰达电子有限公司凭借总公司强大的技术后盾和先进的管理理念,不断提高生产效率和产品质量,已成为集团内最重要的基地之一。

  1. TDK-Lambda电源新品的创新与发展

近年来,TDK-Lambda不断推出具有创新性的电源产品,以满足市场的多样化需求。例如,公司推出的DRB系列DIN导轨安装电源新增了三相交流输入和高功率型号,具有过流保护、低输入浪涌电流等特点,广泛应用于开关柜、分布式机械和工业系统等领域。这些新品的推出不仅进一步巩固了TDK-Lambda在电源领域的领先地位,也为公司带来了更广阔的发展空间。

格莱尔(GLE)公司的发展小趣事

格莱尔始终将技术创新视为企业发展的核心动力。公司不断投入研发资源,引进先进的生产设备和高精度的检测仪器,确保产品质量的稳步提升。同时,格莱尔还通过了ISQ9001质量管理体系和IATF16949汽车质量管理体系认证,全部产品实现了符合RoHS标准的无铅化生产,达到了欧盟的环保要求。这些努力使得格莱尔的产品在市场上赢得了良好的口碑和广泛的认可。

Hosiden Corporation公司的发展小趣事

随着全球市场的不断扩展,Hosiden积极实施全球化战略,以满足全球客户对高质量电子产品的需求。公司不仅在日本本土拥有强大的生产基地和销售网络,还通过设立海外分支机构、与国际知名企业建立战略合作关系等方式,不断拓宽其全球市场版图。例如,Hosiden在中国市场通过投资豪熙电电子(上海)有限公司等方式,加强了其在中国及亚太地区的业务布局。

Cantherm公司的发展小趣事

随着环保意识的日益增强,Cantherm公司积极响应国家号召,将环保理念融入产品设计和生产过程中。公司研发出一系列环保型电子产品,采用可降解材料和节能技术,有效降低了产品对环境的影响。这一举措不仅提升了公司的社会形象,还为公司带来了更多的环保项目合作机会。

A-BRIGHT公司的发展小趣事

A-BRIGHT公司的起点并不起眼,只是电子行业里众多小公司之一。然而,在XXXX年,公司成功研发出了一种新型的高效率LED芯片,这一技术突破使得A-BRIGHT的产品在能效和寿命上大幅超越竞争对手。这一创新迅速吸引了市场的关注,A-BRIGHT的订单量激增,公司开始逐渐崭露头角。

Advanced Linear Devices公司的发展小趣事

A-BRIGHT公司注重与产业链上下游企业的合作与共赢。公司与多家原材料供应商建立了长期稳定的合作关系,确保了原材料的稳定供应和质量。同时,A-BRIGHT也与多家知名的电子产品制造商展开合作,共同开发新产品,实现了资源共享和互利共赢。

问答坊 | AI 解惑

AVR单片机在线编程下载线电路图,PCB图及HEX文件

AVR单片机在线编程下载线电路图,PCB图及HEX文件…

查看全部问答>

wince 5 沙漏(Hourglass)显示问题:点击屏幕,沙漏才有漏沙效果.

刚刚发现的问题,wince 5中用EVC 写应用程序自己调用显示沙漏, 第一种情况:如下,在初始化时显示沙漏持续5s钟,实际效果是,我双击打开应用程序,什么也看不到,如果我点击下屏幕,就会显示出沙漏,如不笔离开屏幕,沙漏也立刻消失.好像只有在点击屏幕是才 ...…

查看全部问答>

切换LCD分辨率时,调色板创建错误,大家来探讨一下!

MINI2440开发板下为了支持动态修改分辨率,在S3C2440DISP:S3C2440DISP()中生成了一个2个元素的数组GPEModeEx  m_ModeInfoEx[2],保存了2个显示模式的分辨率,NumModes()改为返回2,此外其他修改的源代码如下: SCODE S3C2440DISP::GetM ...…

查看全部问答>

ARM下的64位加法运算?

高手们:    在ARM中,哪个能写一个这个程序:  有一个数:123456789ABCDFE    又有一个数987654321FEDCBA   这两个数如何比较大小?    …

查看全部问答>

WINCE中调用connect函数出错

char *sIp=\"192.168.11.105\";         int nPort = 3000;         int rc;         WSADATA  wsaData;         //SOCKET nConnect;   &nb ...…

查看全部问答>

高手帮我看看这个开关电源的图对不对

搞了好几天,总算有点眉目了,第一次画还希望大侠们提些宝贵意见哈。感觉过流保护还不完整,参数有的不会算,大侠们发现了就尽管说哈,教教小弟,多谢啦 [ 本帖最后由 yuelianghudie 于 2010-8-8 15:23 编辑 ]…

查看全部问答>

CH2输入捕获问题

我用TIME2的CH2做输入捕获,数据不对,请大家帮我看一下初始化对不!谢谢! int main(void) { #ifdef DEBUG   debug(); #endif   /* System Clocks Configuration */   RCC_Configuration();  &nb ...…

查看全部问答>

问个C++调试问题(不知道能不能在这里问)

最近在学习C语言,用C++调试程序的时候发现在一个问题,每次我单步运行的时候总会出现如图的东西,这就把我的MAIN程序看不到了,怎么让这个不要显示 [ 本帖最后由 zjjone1023 于 2011-4-18 23:59 编辑 ]…

查看全部问答>

SAMSUNG6410 死机

本帖最后由 jameswangsynnex 于 2015-3-3 20:02 编辑 用6410做了个平台,放着过一段时间,就死机了,不知道什么原因,我HOST USB没有,但没接15K,下拉,不知道,有没有关系 …

查看全部问答>