A4988步进电机驱动器调节驱动力度

特别注意:测量电压的时候千万要小心,不要短路到不该碰到的接点,很可能会造成4988烧毁!!!

特别注意:4988的输出电流,超过1安培的话,必须加装散热片。 超过1.5安培,需要再加风扇。 就算有安装散热片、风扇,输出电流也不应超过2安培。 否则有烧毁的危险。

根据Pololu产品网页上的说明,一般步进马达使用4988驱动时,步进马达实际测量到的电流,大约是4988输出电流上限的0.7倍。 所以需要设定的电流输出上限,会是马达标定的额定电流除以0.7。

4988输出电流上限的计算公式: I=Vref / 8 * Rs
Vref是参考电压,利用可变电阻设计出可以调整Vref的电路,让使用者能够自行调整输出电流上限。

Rs是参考电阻。 目前市面上买的到的4988模组,参考电组有三种,要自己看一下。 Pololu厂商设计的电路,Rs是0.05欧姆;StepStick(Open Source Project)所公布的电路,有0.2及0.1欧姆两种规格。 使用的是SMD 电阻,”R050″代表0.05欧姆;”R200″,代表0.2欧姆;”R10″,代表0.1欧姆。 ( SMD晶片电阻阻值标示方法 )
位置如图:

 

参考电压测量方式

可变电阻的金属螺丝头,就是Vref的测量点,用三用点表的正极做测量。 接地点在图中最右下角的pin针,旁边的丝印记号有标注”GND”。

举例说明

如果你买到的步进马达,额订电流是1.5安培,那4988输出电流上限会是1.5/0.7 = 2.14 安培。
然后再查看4988模组上的Rs,如果是0.2欧姆,那你需要把Vref调整成(1.5/0.7)*8*0.2 = 3.43 伏特。

参考电压速查表

编按: Vref受到控制板上分压电路的限制,不一定能调整出表列的电压。

Rs = 0.2 Ω

马达额订电流(A) 4988输出电流上限(A) Rs(Ω) 4988参考电压Vref应设定成(V)
2 2.86 0.2 4.57
1.9 2.71 0.2 4.34
1.8 2.57 0.2 4.11
1.7 2.43 0.2 3.89
1.6 2.29 0.2 3.66
1.5 2.14 0.2 3.43
1.4 2.00 0.2 3.20
1.3 1.86 0.2 2.97
1.2 1.71 0.2 2.74
1.1 1.57 0.2 2.51
1 1.43 0.2 2.29
0.9 1.29 0.2 2.06
0.8 1.14 0.2 1.83
0.7 1.00 0.2 1.60
0.6 0.86 0.2 1.37
0.5 0.71 0.2 1.14
0.4 0.57 0.2 0.91
0.3 0.43 0.2 0.69
0.2 0.29 0.2 0.46
0.1 0.14 0.2 0.23

Rs = 0.1 Ω

马达额订电流(A) 4988输出电流上限(A) Rs(Ω) 4988参考电压Vref应设定成(V)
2 2.86 0.1 2.29
1.9 2.71 0.1 2.17
1.8 2.57 0.1 2.06
1.7 2.43 0.1 1.94
1.6 2.29 0.1 1.83
1.5 2.14 0.1 1.71
1.4 2.00 0.1 1.60
1.3 1.86 0.1 1.49
1.2 1.71 0.1 1.37
1.1 1.57 0.1 1.26
1 1.43 0.1 1.14
0.9 1.29 0.1 1.03
0.8 1.14 0.1 0.91
0.7 1.00 0.1 0.80
0.6 0.86 0.1 0.69
0.5 0.71 0.1 0.57
0.4 0.57 0.1 0.46
0.3 0.43 0.1 0.34
0.2 0.29 0.1 0.23
0.1 0.14 0.1 0.11

Rs = 0.05 Ω

马达额订电流(A) 4988输出电流上限(A) Rs(Ω) 4988参考电压Vref应设定成(V)
2 2.86 0.05 1.14
1.9 2.71 0.05 1.09
1.8 2.57 0.05 1.03
1.7 2.43 0.05 0.97
1.6 2.29 0.05 0.91
1.5 2.14 0.05 0.86
1.4 2.00 0.05 0.80
1.3 1.86 0.05 0.74
1.2 1.71 0.05 0.69
1.1 1.57 0.05 0.63
1 1.43 0.05 0.57
0.9 1.29 0.05 0.51
0.8 1.14 0.05 0.46
0.7 1.00 0.05 0.40
0.6 0.86 0.05 0.34
0.5 0.71 0.05 0.29
0.4 0.57 0.05 0.23
0.3 0.43 0.05 0.17
0.2 0.29 0.05 0.11
0.1 0.14 0.05 0.06

参考资料
http://www.eng.utah.edu/~cs5789/handouts/a4988_DMOS_microstepping_driver_with_translator.pdf

http://reprap.org/wiki/StepStick
http://reprap.org/wiki/Sanguinololu
http://www.pololu.com/product/1182

AR/QCA SPI 启动原理和 ART 地址定位原理

本贴主要讲解 Bootloader 是如何在使用 SPI Flash 的 AR/QCA 的芯片上启动的,以及 OpenWrt 代码 ar71xx 的 mach 文件中类似于 u8 *art = KSEG1ADDR(0x1fff0000) 中 0x1fff0000 是如何得来的。
楼主之前在 U-Boot 编译教程中进行过简单的描述,但是因为实在是太简略了,所以打算写一个详细版的。

下面楼主将按照必要的顺序依次讲解。

1. CPU 地址、总线地址、映射

对于 MIPS CPU 来说,只有一种地址,即 CPU 地址。32 位 CPU 的寻址范围称为它的地址空间,也就是 4GB,从 0x00000000 到 0xffffffff。
而总线,则是用来连接外设的,外设的寄存器、RAM、ROM等,都要通过总线来访问。总线也有自己的地址空间。

CPU 地址跟总线地址是相互独立的。因此,要让 CPU 能够访问到外设,就必须要让 CPU 地址跟总线地址产生某种关联,这就是映射。
这就好比数学里面的映射。MIPS CPU 上的映射是从 CPU 上一段地址空间到总线上一段地址空间的一一映射。

有了这样的关联后,就很容易通过对 CPU 地址的操作来变成对总线上外设的操作了。

2. AR/QCA 的总线地址布局

以 AR9344 为例,如图:ar9344_1

 

 

 

 

 

可以看到 AR/QCA 的 CPU 使用了总线地址的 0x00000000 ~ 0x1fffffff 共 512MB 的地址空间。
注意到内存也是通过总线来访问的。由图可知 AR/QCA 只有最大 256MB 的内存寻址能力。

3. MIPS 的内存布局

MIPS32 (即 32 位) 的内存模型都是一致的,如图:
addrspace_1

 

 

 

 

 

 

 

(图片来自 MIPS32 74K Processor Core Family Software User’s Manual)

由于 Bootloader 跟 Linux 内核都运行在 Kernel Mode 下,所以这里也只就 Kernel Mode 进行讨论。

由图可以看到,Kernel Mode 下,CPU 的地址空间被分为了5段: kuseg kseg0 kseg1 kseg2 kseg3。
kuseg 空间为 2GB,是用于用户态程序访问用的,kseg2 kseg3 是用作内核的内存分页用的。
这里只重点讨论 kseg0 和 kseg1。kseg0 和 kseg1 都占用 512MB 的地址空间。

由 MIPS 手册可知,kseg0 和 kseg1 都映射到了总线地址上的相同区域,也就是总线地址的 0x00000000 ~ 0x1fffffff 共 512MB 的空间。
这个映射是固定映射,也就是不会经过 MMU 的转换,访问 kseg0 跟 kseg1 都会直接被映射到总线上 0x00000000 ~ 0x1fffffff 的对应位置。

由于 AR/QCA 使用的总线地址空间也是这个范围,因此通过 kseg0 或 kseg1 就都能访问到整个总线地址空间。
如图:
map_1

 

 

 

 

 

 

 

从这里可以看到,kseg0 的范围是 0x80000000 ~0x9fffffff,kseg1 的范围是 0xa0000000 ~ 0xbfffffff。
又,总线地址空间范围是 0x00000000 ~ 0x1fffffff,那么:

1. 从总线地址映射到 kseg0 的方法是:在保证总线地址有效 (即总线地址在 0x00000000 ~ 0x1fffffff 内) 的情况下,将总线地址加上 kseg0 的起始地址,即:
kseg0(addr) = 0x80000000 + addr
2. 从总线地址映射到 kseg1 的方法与从总线地址映射到 kseg0 的方法类似,即:
kseg1(addr) = 0xa0000000 + addr
3. 从 kseg0 和 kseg1 映射到总线的方法是:将 CPU 地址除以 kseg0 或 kseg1 段长度,取余,得到的就是总线地址,即:
bus(addr) = addr % 0x20000000

实际上,在 Linux 内核中,arch/mips/include/asm/addrspace.h 提供了相应的宏来进行上述的地址转换,简化后如下:

#define virt_to_bus(_virt) ((_virt) & 0x1fffffff)
#define KSEG0ADDR(_addr) ((_addr & 0x1fffffff) | 0x80000000)
#define KSEG1ADDR(_addr) ((_addr & 0x1fffffff) | 0xa0000000)
virt_to_bus 即为总 CPU 地址转换到总线地址, 与 0x1fffffff (即低 512MB 的掩码) 进行按位与操作,相当于除以 0x20000000 取余,即舍弃掉 512MB 之上的部分,只剩下低 512MB 的部分;KSEG0ADDR 与 KSEG1ADDR 都先保证输入地址是有效的,再进行转换,这里的按位或运算,在结果上等同于加法运算

虽然 kseg0 跟 kseg1 都映射在总线相同的地址空间上,但是,它们的作用却并不相同:

kseg0 经过了缓存,kseg1 没有经过缓存。

kseg0 经过了缓存,也就是说从这个段读取出来的数据,可能是缓存过的,跟总线上实际的数据可能不同;向其写入的数据,可能会被延迟写入总线。
kseg1 则没有经过缓存,对这个段的任何读写操作都将立即反映在总线上。

所以:
kseg0 主要用于需要加速的内存访问和 ROM 访问
kseg1 主要用于设备寄存器的访问

4. MIPS 上的启动地址

MIPS 的 CPU 在复位后,会从 CPU 地址的 0xbfc00000 开始执行,也就是总线地址的 0x1fc00000。
可以看出 CPU 是在 kseg1 段上开始执行的,这是因为在 CPU 复位后,缓存还没用初始化,可能并不能使用。在不能保证 kseg0 段一定能使用的情况下,那么肯定只有从 kseg1 段开始执行了。

5. SPI Flash 和映射

这里的 SPI Flash 特指 SPI 接口的 NOR Flash (当然也有 SPI NAND Flash)。

NOR Flash 有个特点,即给出一个确切的地址,那么它就能连续输出从这个地址开始的数据。这个特点跟 DRAM 类似,因此它可以被用作启动设备。
这个特性被称为 XIP (eXecute-In-Place)。

为了实现这个特性,就需要 CPU 能够通过 CPU 地址空间访问到 Flash 上的数据。
由于 Flash 是一个外设,因此对它的访问是通过总线来进行的。

这里,又用到了映射:
Flash 有自己的地址空间,即存储数据的地址。
由于 Flash 是外设,因此它的地址空间会被映射在总线上面。这又是一个映射,只不过是从总线到 Flash 的映射。

那么,通过 CPU 访问 Flash,实际上经过了两次映射:第一次是 CPU 地址到总线地址的映射,第二次是总线地址到 Flash 地址的映射。
这样,CPU 就能够直接读取 Flash 的数据了。

6. AR/QCA 的 CPU 在 SPI Flash 上的启动

以 AR9344 为例,其它的型号也都基本相同

AR9344 遵循 MIPS 的要求,CPU 复位后,从 0xbfc00000 开始执行。

那么,总线地址 0x1fc00000 对应了什么外设呢?
从第 2 节可以看出, 0x1f000000 ~ 0x1fffffff 对应的正是 SPI Flash。

但是,Flash 是从 0x1f000000 开始映射的,那么 0x1fc00000 处映射的又是什么呢?

实际上,Flash 确实是从 0x1f000000 开始映射的,总共可以映射 16MB 的 Flash 空间。
为了兼容 MIPS 要求的 0xbfc00000 的复位地址,AR9344 在 0x1fc00000 处又重新对 Flash 进行了一次映射,映射了 Flash 开头的 4MB

但是,如果 0x1fc00000 处映射了 Flash, 那么从 0x1f000000 处就只能访问 12MB 的 Flash 空间了。
因此 AR9344 专门设置了一个寄存器,用来控制是否从 0x1fc00000 处重新映射 Flash。
这样的话,当 Bootloader 完成了启动过程,就可以关闭在 0x1fc00000 的重新映射,这样就能从 0x1f000000 处访问到完整的 16MB 的 Flash 空间了。

7. 如果 Flash 容量小于 16MB,那么会怎样

上一节已经说了,从 0x1f000000 可以映射 16MB 的 Flash 空间,那么如果 Flash 容量小于 16M,会怎么样?

实际上,Flash 对于地址有个回绕功能,也就是说,如果给定的地址超过了 Flash 的地址范围,那么 Flash 会自动让地址变成 0,即又从头开始。
想当于用给出的地址除以 Flash 的容量取余数。
这样对 Flash 来说,地址总是有效的,对外界来说,就像是 Flash 的数据在循环。

例如:某个 Flash 的容量是 4MB,那么它的地址范围就是 0x000000 ~ 0x3fffff。
如果访问 0x400000,就变成了访问 0x000000;如果访问 0x7f0000,就变成了访问 0x3f0000;如果访问 0xff0000,也是变成了访问 0x3f0000。

回到 AR9344 的 16MB 映射,如果 Flash 容量小于 16MB,那么在这 16MB 上的体现就是 Flash 数据重复映射了多次
例如:Flash 是 8MB 的,那么它就在 0x1f000000 和 0x1f800000 上各映射了一次;
如果 Flash 是 4MB 的,那么它就在 0x1f000000、0x1f400000、0x1f800000、0x1fc00000 上各映射了一次;

8. OpenWrt 的 mach 文件中,ART 数据地址的来历

在上面几节说来这么多之后,对于类似于 u8 *art = KSEG1ADDR(0x1fff0000) 这样的地址就应该很好理解了:

假设 ART 位于 Flash 的最后 64KB,那么它在 Flash 中的地址就是 Flash 容量 – 64KB。

例如:
Flash 是 4MB 的,那么 ART 在 Flash 中的起始地址就是 0x400000 – 0x10000 = 0x3f0000;
Flash 是 8MB 的,那么 ART 在 Flash 中的起始地址就是 0x800000 – 0x10000 = 0x7f0000;
Flash 是 16MB 的,那么 ART 在 Flash 中的起始地址就是 0x1000000 – 0x10000 = 0xff0000;

那么,这个地址在总上的映射就是 0x1f000000 + ART 地址,即:
Flash 是 4MB 的,那么 ART 在总线中的起始地址就是 0x1f000000 + 0x3f0000 = 0x1f3f0000;
Flash 是 8MB 的,那么 ART 在总线中的起始地址就是 0x1f000000 + 0x7f0000 = 0x1f7f0000;
Flash 是 16MB 的,那么 ART 在总线中的起始地址就是 0x1f000000 + 0xff0000 = 0x1fff0000;

现在,假设 OpenWrt 并不知道 Flash 的容量:
如果在 mach 中使用 8MB Flash 的 ART 地址 0x1f7f0000,如果 Flash 是 16MB 的,那么通过 0x1f7f0000 就无法获取正确的 ART 数据。

那么解决方法是什么呢:
那就是假设 Flash 都是 16MB 的,这样的话就会使用 0x1fff0000 这个地址。
当 Flash 容量小于 16MB 时,根据上一节所说的地址回绕功能,通过 0xff0000 访问到的就是 Flash 实际最后 64KB 的内容。

这就是 mach 文件中这个地址的来历。

9. 后记

嵌入式设备开发需要掌握很多的知识,并不是只会编程就行了。例如还需要学习计算机组成原理、操作系统原理等等。
很多开发者对这些并不了解,因此对于这些文件都会有相当多的疑问。
楼主尽量将文章内容简化,以使其变得能够容易理解,并希望能够起到抛砖引玉的作用。
希望通过此文让开发者能过对嵌入式设备开发有更深入的了解,消除疑惑。

J-link V8固件升级记

好久没为电子工程事业尽份力了!今天也稍微努把力!写写我是如何升级J-link的固件的吧!

111

 

 

 

 

 

 

J-link是什么?晕,不是电子工程师的退散吧!这是现在比较流行的arm调试工具!我手上是那个大家都比较喜闻乐见的V8版本!盗版吗!大家懂的!50元入手的!没有软件升级与维护的!说不准哪天!升级软件就封杀了!如果固件没法更新就基本一块砖!砸人防身都可以哦!
222

 

 

 

 

 

首先在通电情况下,短接a!然后拔下usb 接着短接b,然后插入usb 10秒,然后拔下usb。最后从新上电插入usb!于是你的电脑里面就有了一个无法识别新设备!

333

 

 

 

 

 

 

 

 

去atmel官网下载最新版本的SAM-BA v2.12软件,你就可以正确识别硬件为一个usb转串口设备了!

http://ishare.iask.sina.com.cn/f/34214872.html

双击运行SAM-BA v2.12

444

 

 

 

 
设置你的设备端口号,还有芯片型号!之后点击连接!

666

 

 

 

 

 

 

 

进入固件刷写窗口!选择好新固件的文件地址!然后点send file

http://ishare.iask.sina.com.cn/f/34231756.html

777

 

 

 

 

 

 
提示是否加密!选择yes!

888

 

 

 

 

 

 
烧录进行中~~~~

999

 

 

 

 

 

 
再次提示是否要加密,选择no!之后退出程序!

拔掉J-link,然后从新插入usb!

1111

 

 

 

 

 

 

 

 

又会有新设备,这个时候要去下载安装J-Link ARM V4.40驱动就有了!

注意一定要是J-Link ARM V4.40 之后的版本都会封杀你的破解!

http://download.csdn.net/detail/wm20031015/3926860  

2222

 

 

 

 

 
运行J-Link ARM V4.40提示升级,选择yes

5555

 

 

 

 

 

 

6666

 

 

 

 
提示升级成功!

从新插拔一下J-link!好了你的J-link V8又复活了!

双击J-Link ARM V4.40 程序正常运行了!

8888

 

 

 

 

 

 

^_^,我能给的也就这么多了!如果还有什么问题,或者说新的4.5.0之后的版本需要破解的话,估计就又得等等了!不过至少现在J-link V8 又可以欢快的陪我们工作一阵子了!

 

install_at91-isp

jlnk_bin_烧录

STM32 的加密实现

目的:对运行于STM32的嵌入式代码程序进行加密

编译环境:IAR Embedded System for ARM5.5

一.STM32Flash组织

1460007975-5260-

STM32的Flash包括主存储器(HD版本,512KB)+信息块。信息块包括2KB的系统存储器(用于系统自举启动代码)和16字节的选项字节(8个字节数据+8个字节数据的反码)。

二、STM32读保护

STM32读保护是通过设置RDP选项字节,然后在系统重新复位加载了新的RDP选项字节后启动的。当保护字节被写入相应的值以后:

●通过从内置SRAM或FSMC执行代码访问主闪存存储器的操作,通过DMA1、DMA2、JTAG、SWV(串行线观察器)、SWD(串行线调试)、ETM和边界扫描方式对闪存的访问都将被禁止。

●只允许从用户代码中对主闪存存储器的读操作(以非调试方式从主闪存存储器启动)。

●第0~3页(小容量和中容量产品),或第0~1页(大容量和互联型产品)被自动加上了写保护,其它部分的存储器可以通过在主闪存存储器中执行的代码进行编程(实现IAP或数据存储等功能),但不允许在调试模式下或在从内部SRAM启动后执行写或擦除操作(整片擦除除外)。

●所有通过JTAG/SWD向内置SRAM装载代码并执行代码的功能依然有效,亦可以通过JTAG/SWD从内置SRAM启动,这个功能可以用来解除读保护。当读保护的选项字节转变为存储器未保护的数值时,将会执行整片擦除过程。

●可以使用系统启动程序解除读保护(此时只需执行系统复位即可重新加载选项字节),芯片自动擦除Flash所有内容。

三.STM32的加密

1.使用系统启动程序STM32 Flash Loader demonstrator将Flash设置为读保护。

所有以调试工具、内置SRAM或FSMC执行代码等方式对主存储器访问的操作将被禁止,只允许用户代码对主Flash存储器的读操作和编程操作(除了Flash开始的4KB区域不能编程)。用户代码允许自主编程可以实现IAP或者数据存储等功能。

这样破解者将不能用调试工具、内置SRAM或者FSMC执行代码等方式读出Flash中的代码。破解者也不能使用系统启动程序读取代码,因为要解除读保护,将执行整个芯片的擦除操作。

2.主程序中使用设备ID保护

即使将Flash设置为读保护,破解者也可以通过IAP下载自己的一段小程序,从而读出Flash中的内容。因此,还需要利用设备的唯一ID进行加密保护。在主程序中,加入对设备唯一ID的检测,这样即使破解者读出了芯片中的二进制码,也不能用这个二进制码去复制新的器件。具体实现方法:

(1)在应用程序中定义1个(32位甚至更多)const变量,变量值全为0xFF。每次启动程序时,检查const变量值如果全为0xFF,就读器件的唯一ID,通过Flash编程写入该const变量中(因为全是0xFF,所以可以编程写入)。

(2)在程序中多个地方检查const变量,如果变量值不为0xFF并且与设备ID不一致,就执行与功能无关代码(比如自擦除)。

这样,即使破解者读出了芯片中的二进制码,因为这份二进制码包含了设备唯一ID,具有唯一性,所以不能复制到其他芯片中。

为了避免破解者利用反汇编,根据芯片ID数据在二进制文件中查找对应相同数据的位置从而破解,可以将ID拆散成不同的组合,并且写到不同且不连续的地方。更进一步,可在程序中检测多份这样的分散ID,以增加反汇编的难度。或者将CPUID进行加密,Flash中存储加密后的结果。

四.程序加密的实现

 

[cpp] view plaincopy
01.//加密后的CPUID
02.volatile const static uint32 CPUIDEncrypt = 0xFFFFFFFF;
03.
04.//写入加密数据
05.void WriteEncrypt(void)
06.{
07.    //第一次烧写:将UID写入到Flash中
08.    if(CPUIDEncrypt==0xFFFFFFFF)
09.   {
10.        uint32_t CpuID[3];
11.        //获取CPU唯一的ID
12.        CpuID[0]=*(vu32*)(UID_BASE);
13.        CpuID[1]=*(vu32*)(UID_BASE+4);
14.        CpuID[2]=*(vu32*)(UID_BASE+8);
15.
16.        //加密算法,很简单的加密算法
17.        uint32_t EncryptCode=(CpuID[0]>>3)+(CpuID[1]>>1)+(CpuID[2]>>2);
18.        FLASH_Unlock();
19.        FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);
20.        FLASH_ProgramWord((uint32_t)&CPUIDEncrypt, EncryptCode);
21.        FLASH_Lock();
22.    }
23.}
24.//判断加密
25.bool JudgeEncrypt(void)
26.{
27.    uint32_t CpuID[4];
28.    //获取CPU唯一的ID
29.    CpuID[0]=*(vu32*)(UID_BASE);
30.    CpuID[1]=*(vu32*)(UID_BASE+4);
31.    CpuID[2]=*(vu32*)(UID_BASE+8);
32.    //加密算法,很简单的加密算法
33.    CpuID[3]=(CpuID[0]>>3)+(CpuID[1]>>1)+(CpuID[2]>>2);
34.    //检查Flash中的UID是否合法
35.    return (CPUIDEncrypt == CpuID[3]);
36.}
1、将写入加密数据和判断加密两个功能分开。写入加密在PrsCtrlTask开始的地方;而判断加密分布到程序的各个角落。

2、非常重要的是CPUID加密值的定义一定要加“volatile”类型:

volatile const static uint32 CPUIDEncrypt = 0xFFFFFFFF;

否则按速度优化编译,在判断加密值,不会重新读取加密值,导致判断出错。

3、在工程选项Options->Debugger->Download中选择: use flash loader

否则主程序中对Flash编程将不成功。

参考资料:

STM32F10x微控制器参考手册(2009年12月第10版).pdf

STM32单片机 如何选择

自从ARM公司2007年首推出Cortex内核,ST凭借基于ARM CORTEX-M3内核的STM32F1,无疑成为了最大的赢家之一。特别是STM32F103系列,更是成为市场上最通用的MCU系列之一。

不过在Cortex-M3内核出来了7年之际,在我看来Cortex-M3内核已经不能算是性价比最高的MCU内核了。反而Cortex-M0+和Cortex-M4优化越来越好。鉴于我个人对ST MCU比较熟悉,我在这里介绍几款比STM32F103系列性价比更高的MCU系列。

STM32F030—-ARM Cortex-M0内核。最高主频48MHZ,特别是STM32F030F4,16K FLASH,4K RAM , TSSOP20封装。价格在3块钱左右。

STM32F042—-同样Cortex-M0内核 。14年初推出的芯片,号称带USB,CAN总线的最便宜的MCU。可以和STM32F103系列 完全 PIN TO PIN 。适用于需要USB功能的小型电脑周边产品。

STM32L053—-Cortex-M0+内核,14年推出。STM32L152系列的芯片我测过功耗,并没有我想象中的如意,比STM32F103略低,但比起市场上其他的低功耗MCU,并没有太明显的优势。但L053确实做得更好,可以详见我的实测笔记http://bbs.21ic.com/icview-835590-1-1.html 。主频32MHZ,最大FLASH 64kb.适用于低功耗要求苛刻的小型产品应用。跟STM32F103 PIN TO PIN

STM32F411–STM32系列中Cortex-M4内核中比较通用还是STM32F407系列,最高主频180MHZ。但这块STM32F401的特点在于其低功耗。运行功耗100uA/mhz,比32L053还略低。但由于是Cortex-M4内核,更方面功能会更强(最高主频84MHZ , FLASH 512kb),十分适用于智能手环等可穿戴类产品。

STM32F303—-各方面跟STM32F103一模一样,除了多了一个浮点运算,对于运算较多,很多Sensor数据处理的产品,可以考虑。

一般纳税人公司与小规模公司的不同

一般纳税人公司与小规模公司的不同

1、一般纳税人容易和一般纳税人作生意,通常大公司都是一般纳税人,因此生意容易做大。
2、一般纳税人的财务、税务、管理要求规范,财务人员要求高,可以减少经营风险、涉税风险。
3、一般纳税人有一定的经营实力才能申请到,因此让客户感到值得信任。
4、一般纳税人取得增值税进项票可以抵扣,税负比较合理,毛利低一点的生意也可以做,因此生意也容易作大。
结论:企业要做大买卖,一定要做一般纳税人!

增值税一般纳税人与小规模纳税人的主要区别就在于,一般纳税人销售货物可以开具增值税专用发票,购进货物可以取得增值税专用发票,在缴纳增值税时按照销项税额与进项税额的差进行纳税;而小规模纳税人在销售货物时不可以开具增值税专用发票,在购进货物时不可以取得增值税专用发票,在缴纳增值税时按照销售收入乘以6%(工业企业)或4%(商业企业)的简易税率计算纳税。

小规模纳税人同一般纳税人相比,有以下两个方面的局限性。一是缴纳增值税时,按照销售收入乘以6%(工业企业)或4%(商业企业)的简易税率计算纳税,而增值税一般纳税人按照销项减进项的方法计算纳税后,应交增值税占销售收入的比例一般要低于6%或4%,有很多企业远远低于这个比率。第二个局限是:小规模纳税人在销售货物时不可以开具增值税专用发票,这样它的购货方就减少了很多,有很多增值税一般纳税人由于不能从小规模纳税人那里取得增值税专用发票用于抵扣税款,取消了与小规模纳税人的业务往来,使小规模纳税人的生产经营减少了市场。因此,从企业的发展远景看,要想实现更大的发展,拓展更大的市场,还是一般纳税人有利一些。

一般纳税人和小规模纳税人的区别:

①使用发票不同。小规模纳税人销售只能使用普通发票,不能使用增值税专用发票,购买货物与一般纳税人相同,可以收普通发票也能收增值税专用发票,二者收取增值税专用发票后帐务处理不同.一般纳税人按价款部分入成本,税款部分入”应交税金–应交增值税–进项税额”帐户;小规模纳税人则按全额进入成本.

②应交税金的计算方法不同。一般纳税人按”抵扣制”计算税金,即按销项减进项后的余额交税.小规模纳税人按销售收入除于(1+适用税率)后的金额再乘税率计算应交税金,工业6%,商业4%。

③税率不同,一般纳税人分为0税率、13%税率、17%税率。小规模纳税人,商业企业按4%;工业企业按6% ,(免税的除外)。

如何申请一般纳税人企业(一般纳税人企业的认定):

一、认定条件:
1)主要从事生产或提供应税劳务(特指加工、修理修配劳务)的:年销售额在100万元以上的,可以认定为一般纳税人,100万以下的为小规模;2)主要从事货物批发零售的:年销售额180万以上的可以认定为一般纳税人,180万以下为小规模。工业企业年销售额在100万以下的,商品流通企业年销售额在180万以下的,属于小规模纳税人;反之,为一般纳税人 。
二、税收管理的规定:
1)一般纳税人:销售货物或提供应税劳务可以开具增值税专用发票;购进货物或应税劳务可以作为当期进项税抵扣;计算方法为销项减进项。
2)小规模:只能使用普通发票;购进货物或应税劳务即使取得了增值税专用发票也不能抵扣;计算方法为销售额×征收率。
三、税率与征收率:
1)一般纳税人:基本税率17%,税法还列举了5类适应13%低税率的货物,还有几项特殊业务按简易办法征收(参照小规模)。还有零税率应税劳务和货物。
2)小规模:商业小规模按4%征收率;商业以为小规模按6%

PWM变模拟信号(积分电路 )

就是简单的积分电路。频率不变,积分后的电平相当于把高电平的电压和对应的时间的面积,平均到一个周期里。基本上占空比是50%,转换的电压,就是最高电压的50%,占空比30%,模拟电压就是30%。如PWM是5V的电平,转换后的直流电压就是2.5V和1.5V.
积分电路的用途
积分电路常见用于黑白和彩色电视机的扫描电路中。

时间常数τ=RC=10000*0.1×10^-6=0.001秒
就是(1毫秒)。

积分电路的结构
积分电路的结构和电阻分压电路也很相似,并且与微分电路更相似,只是把微分电路中的电阻和电容交换位置而已。这也是一个用电容器和电阻器组成的另一种分压电路。但积分电路输入也不是正弦信号,而是脉冲信号,这也是积分电路与其它分压电路的不同之处。

积分电路的要求
在积分电路中,要求RC时间常数(电阻值乘以电容值)远远大于脉冲宽度,这一点是积分电路中电阻和电容必须满足的要求,这是微分电路和积分电路的又一个不同之处。

积分电路的作用
积分电路与微分电路在功能方面表现也是相反的:能够提取输入信号的平均值大小,即低频成份。这中电路功能与电容滤波电路是有点相似,从电路中提取高频成份去填补低频成份,以至达到电路频率大小变化平均。

积分电路的原理
积分电路和微分电路在结构上只是电阻和电容交换位置,从微分电路图中可以想象出积分电路图。积分电路中电路输入矩形脉冲信号U1加在电阻器上,经过电阻器后再在电容器上输出三角脉冲信号U2。这个电路也可以这样理解:在电阻器和电容器串联电路上输入矩形脉冲信号,用示波器查看电路波形,在电阻器前面会是矩形脉冲信号,在电容器前面会是三角脉冲信号。这主要利用电容器储能充电的特性将电路中矩形脉冲信号转变成三角脉冲信号输送到下一级电路中。三角脉冲波比矩形脉冲波相对来说比较平稳,矩形波是明显一起一落,三角波虽然有起伏,但起伏变化没有矩形那么快,这样看来积分电路就和滤波电容的性质差不多了。
对积分电路原理分析过程要根据输入脉冲信号在前沿阶段、平顶阶段和后沿阶段等几种情况来进行:
1、当输入信号矩形脉冲还没有出现时,输入信号电压为零,所以输出信号电压也为零。
2、当输入信号矩形脉冲出现时,输入信号通过电阻对电容进行充电。由于电容内部刚开始没有电荷,所以电容会呈短路状态,也就是刚开始电容所承受的电压为零,输出信号电压也为零。
3、当输入信号矩形脉冲出现后,随着电容充电电荷不断地增加,电容所承受电压也在不断升高,输出信号电压也会随之升高。流过电容的电流近似与输入脉冲信号电压大小成正比,所以输出信号电压大小近似与输入信号电压的积分正比,积分电路由此而得名。
4、当输入信号矩形脉冲消失时,电阻器的电压会突变为零,电容器就会对电阻器放电。输出电路的电压就是电容放电电压,随着放电的进行,电容的电压越来越低,输出电路的电压也随之越来越低。
5、当输入信号矩形脉冲消失后,由于积分电路要求时间常数远远大于脉冲宽度,所以放电速度比较慢,在电容还没有放完电时下一个脉冲信号就又到来。电容因为刚刚放了电而电压低于输入信号电压,这时电容又开始充电,随着充电的进行电容的电压越来越大,输出电压也就越来大。如此反复,一个脉冲又一个脉冲地循环。

analogWrite怎麼做PWM輸出?改PWM頻率,定时器相關

大家都知道在 Arduino UNO 有六支 pin 可以使用 analogWrite( )做 PWM 輸出,
在板子上 pin 旁邊標示有 “~” 符號, analogWrite( ) 可以用來產生模擬電壓,
很多人一定很好奇那是怎麼做到的 ?

首先來看看 PWM 模擬電壓的原理, 這在官網上就有解說了:
     http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM
所謂的 PWM 全稱是 Pulse-Width Modulation (PWM), 其實這也沒啥學問,
就是對 GPIO 腳位不斷的切換 “有電” “沒電”,
每秒鐘循環幾次即為其 Frequency(頻率),
每次”有電”時間佔一個循環的百分比稱為其佔空比(Duty cycle);
以下是官網上的模擬範例:
int pin = 13;
void setup() {
  pinMode(pin, OUTPUT);
}
void loop(){
  digitalWrite(pin, HIGH);
  delayMicroseconds(100); // Approximately 10% duty cycle @ 1KHz
  digitalWrite(pin, LOW);
  delayMicroseconds(1000 – 100);
}
這個範例中, 一個循環是 1000 us = 1ms, 所以一秒循環 1000次, 因此 Frequency 是 1 KHz,
每個循環中, 有電的比率是 100/1000 * 100% = 10%, 所以 duty cycle (佔空比)為 10%;
這樣就可以模擬出 5Volt x 10% = 0.5 Volt 的電壓!
如果真的這樣做, 有好處也有壞處, 官網上已經說了:
好處是任一支 pin 都可這樣用, 包括 Pint 0 到 Pin 13, 以及 Pin A0 到 A5 共 20支 pin 都可以!
壞處卻更多, 首先就是頻率(Frequency)和佔空比(duty cycle)可能受中斷(Interrup)的影響變成不是很準確 !!
最大的壞處是, 在某支 pin 做 PWM 輸出期間都沒辦法做別的事情 !!

既然說這只是示範可以這樣做, 在  Arduino 當然不可能是這麼做,
那 Arduino 是怎麼做的呢?

就是透過 Timer 計時器直接控制 pin 做 PWM 輸出, Arduino UNO 的 MCU 有三個 timer,
其中 timer0 控制 pin 5, pin 6; timer1 控制 pin 9, pin 10; timer 2 控制 pin 11, pin 3;
所以, 我們可以對這些 pin analogWrite(pin, val); 輸出 0 到 255 的 val 值到 pin ;
如果輸出 val 是 0, 它會偷偷直接改用 digitalWrite(pin, 0); 輸出,
如果 val 是 255, 也是會偷偷直接改用 digitalWrite(pin, 1); 輸出!
如果 val 是 1 到 254, 則會下命令請 pin 腳對應的 timer 計時器(定時器)幫忙!!
How ?
首先要知道 timer 的基本知識:
(1)每個 timer 一定有個 counter, 例如 timer0 的TCNT0, timer1 的TCNT1, timer2 的TCNT2;
該 counter 一定是每個 tick 會加 1, 每個 tick 通常是把 CPU 的 clock 拿來經過一個除頻電路,
然後給 timer 使用; Arduino UNO 採用 AVR ATmega328 MCU, 且 clock Rate 是 16MHz,
每個 timer 的除頻 Prescaler 是獨立設定的, 通常可以設 1, 2, 4, 8, 64, 256, or 1024 等,
這必須看 MCU 的 datasheet.

(2)每個 timer 通常提供許多 mode 運作模式, 例如 counter 溢出(Overflow)或Rollover歸零時產生中斷,
或 TCNT? 達到某個值時產生中斷等, Arduino ATmega328 的 timer 有 16種 mode, 許多 Mode 是與 PWM 有關;
要設定 timer 的 Mode 可以透過修改 timer 的控制暫存器, 例如 TCCR?A, TCCR?B,    注意以 ATmega328 為例, TCCR?A 和 TCCR?B 要合起來用, 此處的 A, B 與 channel A, channel B 無關!!

(3)每個 timer 通常有比較暫存器(Compare Register), 當 TCNT? 值與該些比較暫存器相同時可以做某事,
   不一定是對 CPU 產生中斷! Arduino 每個 timer 有兩個比較暫存器, 分別命名 OCR?A 和 OCR?B,
  其中 ? 是 0, 1, 2 分別對應到 timer0, timer1, 和 timer2 這三個計時器.

你可以先偷看 analogWrite( ) 的程序碼:
    在你 Arduino IDE 下的 hardware\arduino\cores\arduino\wiring_analog.c
很簡單, 真正請 timer 幫忙只做三件事: a.找出對應的 port, b.設定控制暫存器, c.填入 analog的值到比較暫存器!
不過你會發現看不太懂, 因為還不知道硬體 timer 控制 PWM 運作方式與原理!
不想看 datasheet 可以參考這:
http://letsmakerobots.com/conten … mers-and-interrupts

以Arduino UNO 的 timer1為例, 在 mode 5 (Fast PWM, 8 bit), 此時, TCNT1 從 0 數到 255, 然後又加 1 就變0, …
通常從 255 (此 mode 的最大值)又加 1 變為 0 之時會產生 OVF 中斷(TIMSK1的TOIE1要 set), 不過這與 PWM 無關!
PWM 不是用 Interrupt  中斷請求做的, 不必麻煩 CPU, CPU 只要下命令給 timer, timer 就會照命令執行PWM工作 !!
    PWM 是利用每個 timer 上的兩個”匹配符合輸出”暫存器(Compare Match Output) COM?A 和 COM?B;
(注意雖是 Compare Match Output, 但暫存器名稱是 COMxy 不是 CMOxy 喔 !)
在timer1 的 mode 5, 又稱 Fast PWM mode, (不過請注意 Arduino 的 init( ) 設定只有 timer0 用這, 另外 timer1 和 timer2 不是用這 mode),
這時可以把 1 到 254 之間的值放入 OCR1A 或 OCR1B 以便控制 pin 9 或 pin 10
的 PWM duty cycle, 1 到 254 分別對應到 (1+1)/256, .., (254+1)/256 的 duty cycle.

會 +1 是硬體電路設計上的關係, data sheet 上說:
   Note that fast PWM holds the output high one cycle longer than the compare register value.
在 TCNT1 等於 0  之時, COM1A and/or COM1B 會輸出(當然要 TCCR1A 內的 COM1A1 and/or COM1B1 有set),
然後在 TCNT1 等於 OCR1A 則關閉 COM1A, 當 TCNT1 等於 OCR1B 則關閉 COM1B,
注意沒有立即關閉, 是延遲一個 tick 才關閉 ! 所以才會多加1, 因為一個循環是 256, 不是 255,如果不延遲加 1, 則輸出 val 是 254 時變成 254/256, 還差一點點, 所以犧牲 1/256, 就是沒有 1/256佔空比 !!

   由於 Arduino 的 init( )把 timer1 的 Prescaler 設定為 64,
(參考在你 Arduino IDE 內的   hardware\arduino\cores\arduino\wiring.c )
且把 timer1 設定為 8-bit phase correct pwm mode, 所以其頻率是 490.196Hz, 不是 976.5625Hz;
所謂的 8-bit phase correct pwm mode, 意思是 TCNT? 從 0 數到 255, 接著又從 255 倒著數回 0,
那何時把 COM1A and/or COM1B 的輸出打開或關閉呢?

根據 datasheet, 在從 0 往上數, 碰到 OCR1A 時把 COM1A 關閉,
後從 255 往回數, 數到 OCR1A 時把 COM1A 打開(有電); 對於 OCR1B 和 COM1B 也是這樣!
這使得 duty cycle (佔空比) 更準確, 也就是 val 1 ~ 254 分別對應到 1/255 到 254/255 的 duty cycle.
但是 Frequency 則不是除以 256, 是要除以 255 再除以 2, 於是: (注意是 255, 不是 256喔!)
Frequency = 16 MHz / 64 / 255 / 2 = 490.196Hz;

timer 2 也是在 init( )被設為 Prescaler 64 的 phase correct pwm (8-bit);
但是, timer0 雖然 Prescaler 也設 64, 但 PWM 是用 Fast PWM mode,
不使用 phase correct mode 是為了避免影響維護 millis( ) 的中斷 timer0 Overflow Interrupt,
即 ISR(TIMER0_OVF_vect) 這中斷處理程序, 否則 millis( ) 和 micros( ) 以及 delay() 都會受到影響 !!
因此 , timer0 控制的 PWM Frequency 976.5625Hz,
    16 MHz / 64 / 256 = 976.5625Hz
注意用 timer0 控制的pin 5, pin 6 之 PWM 的 duty cycle 無法是 1/256, 它是 0 再來就 2/256了!
結論:

timer0 控制 pin 5, pin 6, PWM 頻率 976.5625Hz, duty cycle可以 2/256 ~ 255/256 (對應 1 到254);
timer1 控制 pin 9, pin 10, PWM 頻率 490.196Hz, duty cycle 可以 1/255 ~ 254/255(對應 1 到254);
timer2 控制 pin 11, pin 3, PWM 頻率 與 duty cycle 跟 timer1 控制的相同 !!

Q: 那 PWM 的 Frequency 可不可以更改?
A: 可以, 偷改 timer 的 Prescaler 就可以達到更改 Frequency 的目的 !
但是, 千萬不要更改 timer0 的 Prescaler, 否則 millis( ) 和 micros( ) 以及 delay() 都會受到影響 !!!
以下是以 timer1 控制的 pin 9, pin 10 為例(注意兩個 pin 的頻率相同!)
在你的 setup( ) { 內, 寫如下兩句即可:
      int fff = 3;  // 可以是 1, 2, 3, 4, 5
      TCCR1B = TCCR1B & 0xF8 | fff;
其中 fff 與對應頻率如下:
  fff   Prescaler   Frequency
   1           1        31372.549 Hz
   2           8          3921.569
   3         64            490.196   <–DEFAULT
   4       256           122.549
   5    1024               30.637 Hz

至於 timer2 控制的 pin 11 和 pin 3,
則在 setup( ) { 內寫:
     TCCR2B = TCCR2B & 0xF8 | ?;
此處的 ? 可以有七種:
   ?  Prescaler   Frequency
   1         1       31372.549 Hz
   2         8         3921.569
   3            32          980.392
   4        64         490.196   <–DEFAULT
   5      128         245.098
   6      256         122.549
   7    1024           30.637 Hz

如果你堅持要改 timer0 的 Prescaler, 以更改 pin 5, pin 6 的 PWM 頻率:
(注意 millis( ) 和 micros( ) 以及 delay() 都會受到影響 !! )
則在 setup( ) { 內寫:
     TCCR0B = TCCR0B & 0xF8 | ?;
此處的 ? 可以有五種:
   ?  Prescaler   Frequency
   1          1       362500 Hz
   2          8           7812.5
   3        64             976.5625   <–DEFAULT
   4      256             244.140625
   5    1024               61.03515625 Hz

參考:
http://playground.arduino.cc/Main/TimerPWMCheatsheet
http://www.atmel.com/Images/doc8161.pdf

arduino 更改pwm频率的方法

我们的PWM口只能通过输出占空比来输出模拟量,但是如果要输出1-60KHz或更高的脉冲频率的话,就不好做到啦。我一直在需找解决方案,无意中找到啦,现提供给大家分享,希望能有所帮助。

源代码如下:Here are some usage examples of the function:

// Set pin 9’s PWM frequency to 3906 Hz (31250/8 = 3906)
// Note that the base frequency for pins 3, 9, 10, and 11 is 31250 Hz
setPwmFrequency(9, 8);

// Set pin 6’s PWM frequency to 62500 Hz (62500/1 = 62500)
// Note that the base frequency for pins 5 and 6 is 62500 Hz
setPwmFrequency(6, 1);

// Set pin 10’s PWM frequency to 31 Hz (31250/1024 = 31)
setPwmFrequency(10, 1024);

Please keep in mind that changing the PWM frequency changes the Atmega’s timers and disrupts the normal operation of many functions that rely on time (delay(), millis(), Servo library).

/**
* Divides a given PWM pin frequency by a divisor.
*
* The resulting frequency is equal to the base frequency divided by
* the given divisor:
*   – Base frequencies:
*      o The base frequency for pins 3, 9, 10, and 11 is 31250 Hz.
*      o The base frequency for pins 5 and 6 is 62500 Hz.
*   – Divisors:
*      o The divisors available on pins 5, 6, 9 and 10 are: 1, 8, 64,
*        256, and 1024.
*      o The divisors available on pins 3 and 11 are: 1, 8, 32, 64,
*        128, 256, and 1024.
*
* PWM frequencies are tied together in pairs of pins. If one in a
* pair is changed, the other is also changed to match:
*   – Pins 5 and 6 are paired on timer0
*   – Pins 9 and 10 are paired on timer1
*   – Pins 3 and 11 are paired on timer2
*
* Note that this function will have side effects on anything else
* that uses timers:
*   – Changes on pins 3, 5, 6, or 11 may cause the delay() and
*     millis() functions to stop working. Other timing-related
*     functions may also be affected.
*   – Changes on pins 9 or 10 will cause the Servo library to function
*     incorrectly.
*
* Thanks to macegr of the Arduino forums for his documentation of the
* PWM frequency divisors. His post can be viewed at:
*   http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235060559/0#4
*/
void setPwmFrequency(int pin, int divisor) {
  byte mode;
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if(pin == 3 || pin == 11) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x7; break;
      default: return;
    }
    TCCR2B = TCCR2B & 0b11111000 | mode;
  }
}

提供参考网址:
http://arduino.cc/playground/Code/PwmFrequency
http://arduino.cc/playground/Main/TimerPWMCheatsheet

电脑风扇 PWM频率的资料

2.4  PWM Control Input Signal
The following requirements are measured at the PWM (control) pin of the fan cable connector:
PWM Frequency: Target frequency 25 kHz, acceptable operational range 21 kHz to 28 kHz
Maximum voltage for logic low:  VIL = 0.8 V
Absolute maximum current sourced:  Imax = 5 mA (short circuit current)
Absolute maximum voltage level:  VMax = 5.25 V (open circuit voltage)

摘自Intel的PWM specification