STM32

STM32是STMicroelectronics(意法半导体)推出的一系列基于ARM Cortex-M内核的32位微控制器(MCU)产品。这些微控制器提供了广泛的产品系列,覆盖了多种不同的性能和功能需求,适用于各种应用领域,包括工业控制、汽车电子、消费类电子、医疗设备等。

STM32系列微控制器以其高性能、低功耗、丰富的外设接口和灵活的开发工具而闻名。它们通常具有丰富的存储器、多种通信接口(如UART、SPI、I2C、CAN等)、模拟数字转换器(ADC)、定时器、PWM输出等功能,以满足不同应用场景下的需求。

STM32微控制器通常使用标准的ARM Cortex-M内核,包括Cortex-M0、M0+、M3、M4和M7等,这些内核具有不同的性能和功耗特性,可根据具体应用的需求进行选择。此外,STM32系列还提供了多种封装和引脚配置,以满足不同尺寸和集成度的要求。

STMicroelectronics为STM32系列提供了丰富的开发工具和支持资源,包括基于ARM开发环境的集成开发环境(IDE)、调试器、评估板和参考设计等。这些工具和资源有助于开发人员快速开发和部署他们的应用,并提供了全面的技术支持和文档资料,帮助用户充分发挥STM32微控制器的性能和功能优势。

支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。在 CM3 中,有两个区中实现了位带。其中一个是 SRAM 区的最低 1MB 范围,第二个则是片内外设区的最低 1MB范围。这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。

位带操作的概念其实 30 年前就有了,那还是8051 单片机开创的先河,如今,CM3 将此能力进化,这里的位带操作是 8051 位寻址区的威力大幅加强版。

CM3 使用如下术语来表示位带存储的相关地址:

位带区:支持位带操作的地址区

位带别名:对别名地址的访问最终作用到位带区的访问上(这中途有一个地址映射过程)

在位带区中,每个比特都映射到别名地址区的一个字——这是只有 LSB 有效的字。当一个别名地址被访问时,会先把该地址变换成位带地址。对于读操作,读取位带地址中的一个字,再把需要的位右移到 LSB,并把 LSB 返回。对于写操作,把需要写的位左移至对应的位序号处,然后执行一个原子的“读-改-写”过程。

STM32中的位带(bit-band)操作

STM32中的位带(bit-band)操作

STM32中的位带(bit-band)操作

支持位带操作的两个内存区的范围是:
0x2000_0000‐0x200F_FFFF(SRAM 区中的最低 1MB)
0x4000_0000‐0x400F_FFFF(片上外设区中的最低 1MB)

对 SRAM 位带区的某个比特,记它所在字节地址为 A,位序号为 n(0<=n<=7),则该比特在别名区的地址为:

AliasAddr=0x22000000+((A-0x20000000)*8+n)*4=0x22000000+(A-0x20000000)*32+n*4

对于片上外设位带区的某个比特,记它所在字节的地址为 A,位序号为 n(0<=n<=7),则该比特在别名区的地址为:

AliasAddr=0x42000000+((A-0x40000000)*8+n)*4=0x42000000+(A-0x40000000)*32+n*4

上式中,“*4”表示一个字为 4 个字节,“*8”表示一个字节中有 8 个比特。

这里再不嫌啰嗦地举一个例子:

1. 在地址 0x20000000 处写入 0x3355AACC
2. 读取地址0x22000008。本次读访问将读取 0x20000000,并提取比特 2,值为 1。
3. 往地址 0x22000008 处写 0。本次操作将被映射成对地址 0x20000000 的“读-改-写”操作(原子的),把比特2 清 0。
4. 现在再读取 0x20000000,将返回 0x3355AAC8(bit[2]已清零)。

位带别名区的字只有 LSB 有意义。另外,在访问位带别名区时,不管使用哪一种长度的数据传送指令(字/半字/字节),都把地址对齐到字的边界上,否则会产生不可预料的结果。

///////////////////////////////////////////////////////////////
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考《CM3权威指南》第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C

#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08

//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入

#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入

#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入

#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入

#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入

#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入

#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入

出处:http://www.cnblogs.com/yuandongtao1989/p/6804318.html

围观 442

独立看门狗(iwdg)

一、简介:

其用于检测和解决由软件错误导致的故障,当计数器达到设定的超时时间值时会产生系统复位。其特点为:1、其运用的时钟是由独立的RC振荡器产生的,因此可以在待机和停止模式下运行。2、在看门狗激活后,如果递减计数器的值达到0X000时会产生系统复位。

二、功能简述:

通过向关键字寄存器(IWDG_KR)写入0XCCCC启动独立看门狗,计数器会从复位值0XFFF,递减计数,当计数器的值达到0X000时,产生复位信号。在计数值还未达到0X000时,向IWDG_KR寄存器写入0XAAAA,IWDG_RLR寄存器的值就会重装载到计时器,从而可以避免产生复位(俗称喂狗)。从而可以看出,当软件运行出问题时,在一定的时间内无法做到喂狗的功能时,就会产生系统复位,实现其对软件故障的检测和解决。

三、相关寄存器:

1、关键字寄存器:

关键字寄存器的有效位为位0到位15,位16到位31保留,前边已经介绍过通过向该寄存器中写入0XAAAA,可以使IWDG_RLR寄存器中的值重装载到计数器,避免系统复位。由于IWDG_PR(预分频器寄存器)和IWDG_RLR(重载寄存器)是具有写保护的寄存器,在该寄存器中写入键值0X5555可使能对IWDG_PR和IWDG_RLR的访问。

2、预分频器寄存器:

该寄存器的有效位为位0到位2,其他位保留,通过设置PR[2:0]的值,设定相应的分频系数。

3、重载寄存器:

上面已经提到该寄存器中的值会重装载到计数器中,计数器将会从该值递减计数,由此可见:该寄存器中的值和预分频器寄存器中的值共同决定超时周期。

4、状态寄存器:

该寄存器只有位0和位1为有效位,位0(RVU)为预分频器寄存器的值更新标志位,位1(PVU)为计数器重载值更新标志。

四、相关代码分析:

通过相关库函数对独立看门狗的配置还是相对简单的,其中初始化的过程如下:

IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //使能对IWDG->PR IWDG->RLR的写

IWDG_SetPrescaler(prer); //设置IWDG分频系数

IWDG_SetReload(rlr); //设置IWDG装载值

IWDG_ReloadCounter(); //reload(喂狗)

IWDG_Enable(); //使能看门狗

窗口看门狗(wwdg)

一、简介:

对比独立看门狗来看,所谓的窗口看门狗就是设定了一个窗口值(上限和下限值)。当递减计数器值小于0X40(窗口下限值)时产生复位。在设置的窗口外重载递减计数器也会执行复位。窗口看门狗可以设置提前唤醒中断,当递减计数器等于0X40时会触发该中断,可以在该中断中做喂狗等相关操作。

二、框图:

窗口看门狗的框图如下:对比的框图来看下边的相关介绍!

stm32f10x中iwdg和wwdg的区别

三、工作过程:

通过设置WWDG_CR寄存器的WDGA位可以使能看门狗,递减计数器为控制寄存器的低7位,其中当第7位(即T6)由1变为0(即由0X40递减为0X3F)时就会复位,在配置寄存器低7位存放看门狗上限值,计数器中的值与上限值比较,如果在上限值之上喂狗也会执行复位,这也是窗口看门狗与独立看门狗的不同之处。由此可见,喂狗的时间只能在上限和下限值之间,否则就会执行复位操作。

四、相关寄存器:

1、控制寄存器(WWDG_CR):

前面已经介绍过了,其中有效位为位0到位7,位7(WDGA)为看门狗激活位,位0到位6做计数器。

2、配置寄存器(WWDG_CFR):

该寄存器的有效位为位0到位9,位0到位6前面已经介绍过存放的是计数器的上限值,位7和位8用来设置定时器时基,从而选定相应的时钟分频器。其中位9就是上边介绍到的提前唤醒中断(EWI)。

3、状态寄存器(WWDG_SR):

该寄存器中的有效位只有位0,用来做提前唤醒中断的标志位(EWIF)。

转自: http://www.cnblogs.com/sumsung007/articles/6704913.html

围观 689

STM32F4系列定时器输出PWM频率计算

第一步,了解定时器的时钟多少:

STM32定时器输出PWM频率和步进电机控制速度计算

我们知道AHP总线是168Mhz的频率,而APB1和APB2都是挂在AHP总线上的。

(1)高级定时器timer1, timer8以及通用定时器timer9, timer10, timer11的时钟来源是APB2总线
(2)通用定时器timer2~timer5,通用定时器timer12~timer14以及基本定时器timer6,timer7的时钟来源是APB1总线

从STM32F4的内部时钟树可知:

当APB1和APB2分频数为1的时候,TIM1、TIM8~TIM11的时钟为APB2的时钟,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟;

而如果APB1和APB2分频数不为1,那么TIM1、TIM8~TIM11的时钟为APB2的时钟的两倍,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟的两倍。

因为系统初始化SystemInit函数里初始化APB1总线时钟为4分频即42M,APB2总线时钟为2分频即84M,所以TIM1、TIM8~TIM11的时钟为APB2时钟的两倍即168M,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟的两倍即84M。

知道定时器的时钟源频率我们用定时器做延时就很方便了,只要设定合适的分频系数即可,附一下用中断实现延时的公式:(摘自原子的STM32F4开发指南)

Tout = ((arr+1)*(psc+1))/Tclk;

公式中psc就是分频系数,arr就是计数值,达到这个计数就会发生溢出中断,Tclk就是我上述分析的时钟源频率的倒数。

通过上面的公式我们就可以轻松计算出对应的定时器频率:但是这里我们需要将分频系数固定一个合适的值。设置成多大合适了,这里我们就要来分析一下我们控制系统的中步进电机的细分步距角和减速比了。

已经知道我们电机参数如下:步距角 = 1.8° 细分=16 减速比= 2mm

一圈360°需要的脉冲数 = 360/1.8*16 = 3200 pulse

又因为电机转一圈,对应的距离是2mm, 所以 电机带动轮子走1mm = 3200pulse / 2 = 1600pluse

#define MM_TO_PLUSE 1600//1mm对应的脉冲数

#define PLUSE_TO_MM (1/1600)//一个脉冲对应的距离

#define DIS_MM_TO_PLUSE(dis) ( MM_TO_PLUSE * (dis) ) //将以mm为单位的长度抓换成对应的脉冲数

#define SPEED_TO_PLUSE(speed) ( (speed) *MM_TO_PLUSE ) //将mm/s的速度转换成HZ

到此为止,电机之间脉冲和距离之间的关系已经搞明白了,那我们开始言归正传,如何计算出我们需要的定时器频率输出了?

假设我们系统需要达到30mm/s的速度而且我们用的是timer2,调用宏计算 30mm/s * 1600 = 48000HZ的频率 = 48KHZ。意思就是说们只要定时器输出的PWM能够满足48KHZ的频率就可以了。

将上面的公式换算成 输出频率 = 定时器的时钟频率(注意是时钟频率不是输出频率)/(分频系数 + 1)/( 计数值+1)

将psc = 0;分频系数为1 ,内部自动加1 ,带入上面的公式就可以计算出计数值 = 1000。就可以输出对应的速度了。

#define TIMER_CLK (48000000/1) //48Mhz 不分频

#define CALC_ARR(speed) (TIMER_CLK /(speed)*MM_TO_PLUSE )

知道速度值就可以调用CALC_ARR宏返回对应的ARR寄存器值啦,我们就可以根据机器的系统参数来控制了。注意,速度不能高于30000ms/s = 30m/s的速度。因为定时的的最大频率就是48MHZ 。

转自: wolf_man9999

围观 653

一、在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。

①HSI是高速内部时钟,RC振荡器,频率为8MHz。

②HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。

③LSI是低速内部时钟,RC振荡器,频率为40kHz。

④LSE是低速外部时钟,接频率为32.768kHz的石英晶体。

⑤PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。

二、在STM32上如果不使用外部晶振,OSC_IN和OSC_OUT的接法:如果使用内部RC振荡器而不使用外部晶振,请按照下面方法处理:

①对于100脚或144脚的产品,OSC_IN应接地,OSC_OUT应悬空。

②对于少于100脚的产品,有2种接法:第1种:OSC_IN和OSC_OUT分别通过10K电阻接地。此方法可提高EMC性能;第2种:分别重映射OSC_IN和OSC_OUT至PD0和PD1,再配置PD0和PD1为推挽输出并输出'0'。此方法可以减小功耗并(相对上面)节省2个外部电阻。

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

01、将RCC寄存器重新设置为默认值 RCC_DeInit;
02、打开外部高速时钟晶振HSE RCC_HSEConfig(RCC_HSE_ON);
03、等待外部高速时钟晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp();
04、设置AHB时钟 RCC_HCLKConfig;
05、设置高速AHB时钟 RCC_PCLK2Config;
06、设置低速速AHB时钟 RCC_PCLK1Config;
07、设置PLL RCC_PLLConfig;
08、打开PLL RCC_PLLCmd(ENABLE);
09、等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
10、设置系统时钟 RCC_SYSCLKConfig;
11、判断是否PLL是系统时钟 while(RCC_GetSYSCLKSource() != 0x08)
12、打开要使用的外设时钟 RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()

四、下面是STM32软件固件库的程序中对RCC的配置函数(使用外部8MHz晶振)

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

* Function Name : RCC_Configuration
* Description : RCC配置(使用外部8MHz晶振)
* Input : 无
* Output : 无
* Return : 无

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

void RCC_Configuration(void)
{
/*将外设RCC寄存器重设为缺省值*/
RCC_DeInit();

/*设置外部高速晶振(HSE)*/
RCC_HSEConfig(RCC_HSE_ON); //RCC_HSE_ON——HSE晶振打开(ON)

/*等待HSE起振*/
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS) //SUCCESS:HSE晶振稳定且就绪
{

/*设置AHB时钟(HCLK)*/
RCC_HCLKConfig(RCC_SYSCLK_Div1); //RCC_SYSCLK_Div1——AHB时钟= 系统时钟

/* 设置高速AHB时钟(PCLK2)*/
RCC_PCLK2Config(RCC_HCLK_Div1); //RCC_HCLK_Div1——APB2时钟= HCLK

/*设置低速AHB时钟(PCLK1)*/
RCC_PCLK1Config(RCC_HCLK_Div2); //RCC_HCLK_Div2——APB1时钟= HCLK / 2

/*设置FLASH存储器延时时钟周期数*/
FLASH_SetLatency(FLASH_Latency_2); //FLASH_Latency_2 2延时周期

/*选择FLASH预取指缓存的模式*/
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); // 预取指缓存使能

/*设置PLL时钟源及倍频系数*/
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

// PLL的输入时钟= HSE时钟频率;RCC_PLLMul_9——PLL输入时钟x 9

/*使能PLL */

RCC_PLLCmd(ENABLE);

/*检查指定的RCC标志位(PLL准备好标志)设置与否*/

while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/*设置系统时钟(SYSCLK)*/

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

//RCC_SYSCLKSource_PLLCLK——选择PLL作为系统时钟

/* PLL返回用作系统时钟的时钟源*/
while(RCC_GetSYSCLKSource() != 0x08) //0x08:PLL作为系统时钟
{
}
}

/*使能或者失能APB2外设时钟*/

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |

RCC_APB2Periph_GPIOC , ENABLE);
//RCC_APB2Periph_GPIOA GPIOA时钟
//RCC_APB2Periph_GPIOB GPIOB时钟
//RCC_APB2Periph_GPIOC GPIOC时钟
//RCC_APB2Periph_GPIOD GPIOD时钟
}

五、时钟频率

STM32F103内部8M的内部震荡,经过倍频后最高可以达到72M。目前TI的M3系列芯片最高频率可以达到80M。

在stm32固件库3.0中对时钟频率的选择进行了大大的简化,原先的一大堆操作都在后台进行。系统给出的函数为SystemInit()。但在调用前还需要进行一些宏定义的设置,具体的设置在system_stm32f10x.c文件中。

文件开头就有一个这样的定义:

//#define SYSCLK_FREQ_HSE HSE_Value
//#define SYSCLK_FREQ_20MHz 20000000
//#define SYSCLK_FREQ_36MHz 36000000
//#define SYSCLK_FREQ_48MHz 48000000
//#define SYSCLK_FREQ_56MHz 56000000
#define SYSCLK_FREQ_72MHz 72000000

ST 官方推荐的外接晶振是 8M,所以库函数的设置都是假定你的硬件已经接了 8M 晶振来运算的.以上东西就是默认晶振 8M 的时候,推荐的 CPU 频率选择.在这里选择了:
#define SYSCLK_FREQ_72MHz 72000000
也就是103系列能跑到的最大值72M

然后这个 C文件继续往下看

#elif defined SYSCLK_FREQ_72MHz
const uint32_t SystemFrequency = SYSCLK_FREQ_72MHz;
const uint32_t SystemFrequency_SysClk = SYSCLK_FREQ_72MHz;
const uint32_t SystemFrequency_AHBClk = SYSCLK_FREQ_72MHz;
const uint32_t SystemFrequency_APB1Clk = (SYSCLK_FREQ_72MHz/2);
const uint32_t SystemFrequency_APB2Clk = SYSCLK_FREQ_72MHz;

这就是在定义了CPU跑72M的时候,各个系统的速度了.他们分别是:硬件频率,系统时钟,AHB总线频率,APB1总线频率,APB2总线频率.再往下看,看到这个了:
#elif defined SYSCLK_FREQ_72MHz
static void SetSysClockTo72(void);

这就是定义 72M 的时候,设置时钟的函数.这个函数被 SetSysClock ()函数调用,而
SetSysClock ()函数则是被 SystemInit()函数调用.最后 SystemInit()函数,就是被你调用的了

所以设置系统时钟的流程就是:

首先用户程序调用 SystemInit()函数,这是一个库函数,然后 SystemInit()函数里面,进行了一些寄存器必要的初始化后,就调用 SetSysClock()函数. SetSysClock()函数根据那个#define SYSCLK_FREQ_72MHz 72000000 的宏定义,知道了要调用SetSysClockTo72()这个函数,于是,就一堆麻烦而复杂的设置~!@#$%^然后,CPU跑起来了,而且速度是 72M. 虽然说的有点累赘,但大家只需要知道,用户要设置频率,程序中就做的就两个事情:

第一个: system_stm32f10x.c 中 #define SYSCLK_FREQ_72MHz 72000000
第二个:调用SystemInit()

转自: kevinhg

围观 440

在做一款消费电子产品时,需要采集电池电压(3.3V-4.2V),同时在休眠的时候希望尽量减小待机电流。电池电压采集电路采用两个1%的300K电阻进行分压,由该电路引起的待机电路为4.2/(300+300)mA=7uA.此时比较合理(整机的待机电流要求30uA以内)。

初始设计电路如下:

STM32采集AD的输入阻抗问题

在编程采集数据时发现测试电压与实际电压有偏差,测试值总比实际值偏小一点。在软件上做补偿,把值修正了。

但是换一个板子测试的时候发现测试的电压又不准了,此时知道通过软件补偿这种方法行不通。那么只能从硬件找原因。

查找datasheet发现AD的输入阻抗最大只有50KΩ。

STM32采集AD的输入阻抗问题

图中RAIN:外部输入阻抗,STM32芯片中这个值最大为50KΩ;

RADC:采样开关电阻,最大值为1KΩ;

CADC:内部采样和保持电容,最大值为8pF.

在ADC数据采集的时候需要有电流流入,那么RAIN会产生一个压降。阻容网络中的RADC和CADC上,对电容的充电由RADC控制。随着源电阻(RADC)的增加,对保持电容的充电时间也相应增加。

对CADC的充电由RAIN+RADC控制,因此充电时间常数为tc = (RADC + RAIN) × CADC。如果时间过短,ADC转换的数值会小于实际值。

通过以上数据知道,采集精度跟采集时间和输入阻抗有关。但是通过计算得知,如果输入阻抗为300KΩ,那么充电时间约为2.4uS。在软件上把采样周期调到最大(ADC_SampleTime_239_5Cycles,频率为12M,时间19.9uS),还是存在误差。说明此时跟周期不是主要原因。

问题出在输如阻抗大于IC里ADC允许的最大阻抗。充电时电流分两路,一路经过R1到R2到地,还有一路经过R1流入MCU的AD接口。(不知是不是IO口会有一定的漏电流到地,IL)此时相当于在R2旁边并了一个电阻到地,检测点的电压不是标准的1/2Vbat.

那么为了更准确地检测电池电压,那么只好把电阻改小。如果选两个50K的电阻,那么此处带来的电流会后42uA.所以在电路上做了个调整:

STM32采集AD的输入阻抗问题

原来接地的地方改接到一个IO口,在需要检测的时候输出低电平,不需要的时候输出高电平。然后分压电阻使用两个30K的问题得到解决,电压检测误差小于0.02V,待机电流比原来的还小了几个微安。

转自: 何言之-博客园

围观 1219

基于STM平台且满足实时控制要求操作系统,有以下5种可供移植选择。分别为μClinux、μC/OS-II、eCos、FreeRTOS和rt-thread。下面分别介绍这五种嵌入式操作系统的特点及不足,通过对比,读者可以根据自己的应用需求选择合适的平台。

TOP1:μClinux

μClinux是一种优秀的嵌入式Linux版本,其全称为micro-control Linux,从字面意思看是指微控制Linux。同标准的Linux相比,μClinux的内核非常小,但是它仍然继承了Linux操作系统的主要特性,包括良好的稳定性和移植性、强大的网络功能、出色的文件系统支持、标准丰富的API,以及TCP/IP网络协议等。因为没有MMU内存管理单元,所以其多任务的实现需要一定技巧。

μClinux在结构上继承了标准Linux的多任务实现方式,分为实时进程和普通进程,分别采用先来先服务和时间片轮转调度,仅针对中低档嵌入式CPU特点进行改良,且不支持内核抢占,实时性一般。

在内存管理上由于μClinux是针对没有MMU的处理器设计的,不能使用处理器的虚拟内存管理技术,只能采用实存储器管理策略。系统使用分页内存分配方式,在启动时对实际存储器进行分页。系统对内存的访问是直接的,操作系统对内存空间没有保护,多个进程可共享一个运行空间,所以,即使是一个无特权进程调用一个无效指针也会触发一个地址错误,并有可能引起程序崩溃甚至系统崩溃。

μClinux操作系统的中断管理是将中断处理分为两部分:顶半处理和底半处理。在顶半处理中,必须关中断运行,且仅进行必要的、非常少、速度快的处理,其他处理交给底半处理;底半处理执行那些复杂、耗时的处理,而且接受中断。因为系统中存在有许多中断的底半处理,所以会引起系统中断处理的延时。

μClinux对文件系统支持良好,由于μClinux继承了Linux完善的文件系统性能,它支持ROMFS、NFS、ext2、MS-DOS、JFFS等文件系统。但一般采用ROMFS文件系统,这种文件系统相对于一般的文件系统(如ext2)占用更少的空间。但是ROMFS文件系统不支持动态擦写保存,对于系统需要动态保存的数据须采用虚拟RAM盘/JFFS的方法进行处理。

在对硬件的支持上,由于μClinux继承了Linux的大部分性能,所以至少需要512KB的RAM空间,lMB的ROM/Flash空间。

在μClinux的移植方面,μClinux是Linux针对嵌入式系统的一种改良,其结构比较复杂。移植μClinux,目标处理器除了需要修改与处理器相关的代码外,还需要足够容量的外部ROM和RAM。

点评:μClinux最大特点在于针对无MMU处理器设计,这对于没有MMU功能的stm32f103来说是合适的,但移植此系统需要至少512KB的RAM空间,1MB的ROM/FLASH空间,而stmf103拥有256K的FLASH,需要外接存储器,这就增加了硬件设计的成本。μClinux结构复杂,移植相对困难,内核也较大,其实时性也差一些,若开发的嵌入式产品注重文件系统和与网络应用则μClinux是一个不错的选择。

TOP2:μC/OS-II

μC/OS-II是在μC/OS的基础上发展起来的,是用C语言编写的一个结构小巧、抢占式的多任务实时内核。μC/OS-II能管理64个任务,并提供任务调度与管理、内存管理、任务间同步与通信、时间管理和中断服务等功能,具有执行效率高、占用空间小、实时性能优良和扩展性强等特点。

对于实时性的满足上,由于μC/OS-II内核是针对实时系统的要求设计实现的,所以只支持基于固定优先级抢占式调度;调度方法简单,可以满足较高的实时性要求。

在内存管理上,μC/OS-II把连续的大块内存按分区来管理,每个分区中都包含整数个大小相同的内存块,但不同分区之间内存的大小可以不同。用户动态分配内存时,只须选择一个适当的分区,按块来分配内存,释放时将该块放回到以前所属的分区,这样就消除了因多次动态分配和释放内存所引起的碎片问题。

μC/OS-II中断处理比较简单。一个中断向量上只能挂一个中断服务子程序ISR,而且用户代码必须都在ISR(中断服务程序)中完成。ISR需要做的事情越多,中断延时也就越长,内核所能支持的最大嵌套深度为255。

在文件系统的支持方面,由于μC/OS-II是面向中小型嵌入式系统的,即使包含全部功能,编译后内核也不到10 KB,所以系统本身并没有提供对文件系统的支持。但是μC/OS-II具有良好的扩展性能,如果需要也可自行加入文件系统的内容。

在对硬件的支持上,μC/OS-II能够支持当前流行的大部分CPU,μC/OS-II由于本身内核就很小,经过裁剪后的代码最小可以为2KB,所需的最小数据RAM空间为4 KB,μC/OS-II的移植相对比较简单,只需要修改与处理器相关的代码就可以。

点评:μC/OS-II是一个结构简单、功能完备和实时性很强的嵌入式操作系统内核,针对于没有MMU功能的CPU,它是非常合适的。它需要很少的内核代码空间和数据存储空间,拥有良好的实时性,良好的可扩展性能,并且是开源的,网上拥有很多的资料和实例,所以很适合向stm32f103这款CPU上移植。

TOP3:eCos

eCos(embedded Configurable operating system),即嵌入式可配置操作系统。它是一个源代码开放的可配置、可移植、面向深度嵌入式应用的实时操作系统。最大特点是配置灵活,采用模块化设计,核心部分由小同的组件构成,包括内核、C语言库和底层运行包等。每个组件可提供大量的配置选项(实时内核也可作为可选配置),使用eCos提供的配置工具可以很方便地配置,并通过不同的配置使得eCos能够满足不同的嵌入式应用要求。

在实时性反面,由于eCos调度方法丰富,提供了两种基于优先级的调度器(即位图调度器和多级队列调度器),允许用户在进行配置时选择其中一个调度器,适应性好。因此在实时性方面表现良好。

在内存管理上eCos对内存分配既不分段也不分页,而是采用一种基于内存池的动态内存分配机制。通过两种内存池来实现两种内存管理方法:一种是变长的内存池;另一种是定长的内存池,类似于VxWorks的管理方案。

在中断管理上eCos使用了分层式中断处理机制,把中断处理分为传统的ISR(中断服务程序)和滞后中断服务程序DSR(递延服务程序)。类似于μClinux的处理机制,这种机制可以在中断允许时运行DSR,因此在处理较低优先级中断时允许高优先级的中断和处理。为了极大地缩短中断延时,ISR应当可以快速运行。如果中断引起的服务量少,则ISR可以单独处理中断;如果中断服务复杂,则ISR只屏蔽中断源,然后交由DSR(递延服务程序)处理。

eCos操作系统的可配置性非常强大,用户可以自己加入所需的文件系统。eCos操作系统同样支持当前流行的大部分嵌入式CPU,eCos操作系统可以在16位、32位和64位等不同体系结构之间移植。eCos由于本身内核就很小,经过裁剪后的代码最小可以为10 KB,所需的最小数据RAM空间为10 KB。

在系统移植方面 eCos操作系统的可移植性很好,要比μC/OS-II和μClinux容易。

点评:eCos最大特点是配置灵活,并且支持无MMU的CPU的移植,开源且具有很好的移植性,也比较合适于移植到STM32平台的CPU上。但eCOS的应用还不是太广泛,还没有像μC/OS-II那样普遍,并且资料也没有μC/OS-II多。eCos适合用于一些商业级或工业级对成本敏感的嵌入式系统,例如消费电子领域中的一些应用。

TOP4:FreeRTOS

由于RTOS需占用一定的系统资源(尤其是RAM资源),只有μC/OS-II、embOS、salvo、FreeRTOS等少数实时操作系统能在小RAM单片机上运行。相对于C/OS-II、 embOS等商业操作系统,FreeRTOS操作系统是完全免费的操作系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行,其最新版本为6.0版。

作为一个轻量级的操作系统,FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能等,可基本满足较小系统的需要。 FreeRTOS内核支持优先级调度算法,每个任务可根据重要程度的不同被赋予一定的优先级,CPU总是让处于就绪态的、优先级最高的任务先运行。 FreeRT0S内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用 时间。

FreeRTOS的内核可根据用户需要设置为可剥夺型内核或不可剥夺型内核。当 FreeRTOS被设置为可剥夺型内核时,处于就绪态的高优先级任务能剥夺低优先级任务的CPU使用权,这样可保证系统满足实时性的要求;当 FreeRTOS被设置为不可剥夺型内核时,处于就绪态的高优先级任务只有等当前运行任务主动释放CPU的使用权后才能获得运行,这样可提高CPU的运行 效率。

FreeRTOS的移植:FreeRTOS操作系统可以被方便地移植到不同处理器上工作,现已提供了ARM、MSP430、 AVR、PIC、C8051F等多款处理器的移植。FrceRTOS在不同处理器上的移植类似于μC/0S一II,故本文不再详述FreeRTOS的移 植。此外,TCP/IP协议栈μIP已被移植到FreeRTOS上,具体代码可见FreeRTOS网站。

点评:相对于常见的μC/OS—II操作系统,FreeRTOS操作系统既有优点也存在不足。其不足之处, 一方面体现在系统的服务功能上,如FreeRTOS只提供了消息队列和信号量的实现,无法以后进先出的顺序向消息队列发送消息;另一方 面,FreeRTOS只是一个操作系统内核,需外扩第三方的GUI(图形用户界面)、TCP/IP协议栈、FS(文件系统)等才能实现一个较复杂的系统, 不像μC/OS-II可以和μC/GUI、μC/FS、μC/TCP-IP等无缝结合。

TOP5:RT-Thread

RT-Thread 是一款主要由中国开源社区主导开发的开源实时操作系统(许可证GPLv2)。实时线程操作系统不仅仅是一个单一的实时操作系统内核,它也是一个完整的应用系统,包含了实时、嵌入式系统相关的各个组件:TCP/IP协议栈,文件系统,libc接口,图形用户界面等。

中国人自己开发的,稳定版本是 1.2.1,有希望看完源码。精简、靠谱,自带一个叫做 finsh 的片上调试工具,非常实用。各种信号量、互斥锁、邮箱、事件等线程协同功能都有。

需要注意的是,rt-thread 2.0 版本的设计思想和 1.2 的完全不同,将会把 linux 纳入进来,是的,不是在 linux 里面嵌入 rt-thread,而是把 linux 嵌入到 rt-thread 里面!

点评:rt-thread 的文档呢,官网是有的,不过,真的是只能作为参考,很明显是开发人员的事后开发笔记整理的。目前还是只能通过看代码来理解详细的使用方式,从文档和论坛的只言片语里面,是难以还原真相的。rt-thread 的好处就是它的版本还比较小,即便缺乏文档,也是可以看源码看下去的。

转自: 嵌入式资讯精选

围观 367

RCC(Reset Clock Controller) —— 复位与时钟控制

一、复位

STM32F10xxx支持三种复位形式,分别为系统复位、上电复位和备份区域复位。

系统复位:除了时钟控制器的RCC_CSR寄存器中的复位标志位和备份区域中的寄存器以外,系统
复位将复位所有寄存器至它们的复位状态。

电源复位:将复位除了备份区域外的所有寄存器。

备份区域复位:备份区域拥有两个专门的复位,它们只影响备份区域。

stm32之RCC寄存器学习

二、时钟

有四种时钟:

高速外部时钟信号(HSE)—— HSE外部晶体/陶瓷谐振器 、HSE用户外部时钟
高速内部时钟信号(HSI)—— 由内部8MHz的RC振荡器产生
低速外部时钟信号(LSE)—— 32.768kHz的低速外部晶体或陶瓷谐振器
低速内部时钟信号(LSI)—— LSI时钟频率大约40kHz(在30kHz和60kHz之间)

时钟的输出:微控制器允许输出时钟信号到外部MCO引脚。 可以时钟配置寄存器来选择输出的时钟。

stm32之RCC寄存器学习

其中:

PLLMUL 用于设置 STM32 的 PLLCLK, STM32 支持 2~16 倍频设置。我们常用
的是 8M 外部晶振+9 倍频设置,刚好得到 72Mhz 的 PLLCLK。

SW 是 STM32 的 SYSCLK(系统时钟)切换开关,从上图可以看出, SYSCLK 的
来源可以是 3个:HSI、PLLCLK和 HSE。

CSS是时钟安全系统,可以通过软件被激活。一旦其被激活,时钟监测器将在HSE振荡器启动延迟后被
使能,并在HSE时钟关闭后关闭 。

三、时钟启动过程

1、开机或复位时使用内部时钟
2、用软件进行切换,尝试开启外部时钟
3、如果开启成功,则使用外部时钟,否则使用内部

四、配置时钟的步骤

1、APB1、APB2的外设接口复位结束(即RESET),关闭APB1、APB2的外设时钟
打开内部8MHz振荡器,复位RCC->CFGR中的SW[1:0]、HPRE[3:0]、PRE1[2:0]、PRE2[2:0]、ADCPRE[2:0]、MCO[2:0]
复位RCC->CR中的HSEON、CSSON、PLLON、HSEBYP
复位RCC->CFGR中的PLLSRC、PLLXTPRE、PLLMUL[3:0]、USBPRE
关闭RCC->CIR中的所有中断
2、使能外部高速时钟晶振HSE
3、等待外部高速时钟晶振工作稳定
4、设置AHB时钟的预分频(在这之前要先执行FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); FLASH_SetLatency(FLASH))
5、设置APB1时钟的预分频
6、设置APB2时钟的预分频
7、设置PLL的时钟源以及PLL的倍频数,然后使能PLL
8、等待PLL工作稳定
9、选择SYSCLK的时钟源
10、判断PLL是否是系统时钟(若选择SYSCLK的时钟源是PLL的话)
11、打开要使用的外设时钟

五、代码

stm32之RCC寄存器学习

仿真结果为:

stm32之RCC寄存器学习

转自: Recca-博客

围观 814

I2C总线是由NXP(原PHILIPS)公司设计,有十分简洁的物理层定义,其特性如下:

• 只要求两条总线线路:一条串行数据线SDA,一条串行时钟线SCL;

• 每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机关系软件设定地址,主机可以作为主机发送器或主机接收器;

• 它是一个真正的多主机总线,如果两个或更多主机同时初始化,数据传输可以通过冲突检测和仲裁防止数据被破坏;

• 串行的8 位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s;

• 连接到相同总线的IC 数量只受到总线的最大电容400pF 限制。

其典型的接口连线如下:

STM32的I2C通信

I2C的协议很简单:

数据的有效性

在传输数据的时候,SDA线必须在时钟的高电平周期保持稳定,SDA的高或低电平状态只有在SCL 线的时钟信号是低电平时才能改变 。

起始和停止条件

SCL 线是高电平时,SDA 线从高电平向低电平切换,这个情况表示起始条件;

SCL 线是高电平时,SDA 线由低电平向高电平切换,这个情况表示停止条件。

字节格式

发送到SDA 线上的每个字节必须为8 位,每次传输可以发送的字节数量不受限制。每个字节后必须处理一个响应位。

应答响应

数据传输必须带响应,相关的响应时钟脉冲由主机产生。在响应的时钟脉冲期间发送器释放SDA 线(高)。   

在响应的时钟脉冲期间,接收器必须将SDA 线拉低,使它在这个时钟脉冲的高电平期间保持稳定的低电平。

也就是说主器件发送完一字节数据后要接收一个应答位(低电平),从器件接收完一个字节后要发送一个低电平。

寻址方式(7位地址方式)

第一个字节的头7 位组成了从机地址,最低位(LSB)是第8 位,它决定了传输的 普通的和带重复开始条件的7位地址格式方向。第一个字节的最低位是

“0”,表示主机会写信息到被选中的从机;

“1”表示主机会向从机读信息。
当发送了一个地址后,系统中的每个器件都在起始条件后将头7 位与它自己的地址比较,如果一样,器件会判定它被主机寻址,至于是从机接收器还是从机发送器,都由R/W 位决定。

仲裁

I2C是所主机总线,每个设备都可以成为主机,但任一时刻只能有一个主机。

stm32至少有一个I2C接口,提供多主机功能,可以实现所有I2C总线的时序、协议、仲裁和定时功能,支持标准和快速传输两种模式,同时与SMBus 2.0兼容。

转自: 博乐Bar

围观 477

本文选用了意法半导体公司基于ARM最新Cortex—M3内核的STM32F103RB作为主控芯片,通过选择合适的液晶模块,构建了一个高性能低功耗的中文人机界面系统。

1、系统的工作原理

本系统以STM32F103RBT6为核心,采用晶彩光电的AM240320TFT液晶屏作为显示器,完成内容的显示,由于STM32F103RBT6内部Flash为128K,如果用来储存汉字字库,对芯片资源是一种极大的浪费,所以本文中采用微控制器外挂SPI接口Flash的设计思路,将不用重复改变的中文字库存放在外部Flash芯片里面,需要时再通过SPI口调入处理器。由于STM32F103RBT6不带有FSMC,所以采用软件模拟总线的方法,完成对液晶模块的驱动。

2、系统硬件设计

2.1、供电部分电路

由于整个系统采用3.3V供电,所以必须外部稳压电路将电压稳定到3.3V,本设计中采用三端稳压芯片LM1117-3.3,将外部电池电压稳定为3.3V位系统提供电源,为处理器、液晶显示器、SPIFlash供电,采用二极管IN4007串接在电源正极,为系统提供电源反接保护。供电部分原理图如图1所示。

基于STM32的高性能低功耗人机界面系统设计
图1 系统供电部分原理图

2.2、液晶显示部分电路设计

液晶显示部分主要由微控制器驱动液晶显示模块完成人机界面状态的显示,通过发送命令字,完成液晶模块的初始化以及汉字的显示。

2.2.1、STM32F系列ARM微控制器的特点

STM32处理器采用ARM公司最新的V7体系架构的内核Cortex—M3,它的速度比ARM7快三分之一,功耗低四分之三,同时集成了分支预测,单周期乘法,硬件除法等功能,大大地提高了处理器的数据处理能力,同时采用最新的Thumb-2指令集,有效地降低了代码的密度,提高了程序的执行效率,通过对功耗和性能的分析,本文中采用的处理器为STM32F103RBT6,该处理器工作频率为72MHz,内置高速存储器(高达128K字节的闪存和20K字节的SRAM),丰富的增强I/O端口和联接到2条APB总线的外设。供电电压2.0~3.6V,一系列的省电模式保证低功耗应用的要求,达到了性能和功耗的平衡。

2.2.2、TFT液晶显示模块的特点

TFT液晶显示屏是薄膜晶体管型液晶显示屏。TFT液晶为每个像素都设有一个半导体开关,每个像素都可以通过点脉冲直接控制,因而每个节点都相对独立,并可以连续控制。不仅提高了显示屏的反应速度,同时可以精确控制显示色阶,所以TFT液晶的色彩更真。

由于大多数带有LCD控制器的ARM处理器都没有内部的程序存储器和数据存储器,而一般的Cortex—M3内核微控制器都不带有专门的LCD控制器,对于不带有LCD控制器的系统,一般长常用Intel8080接口或者Motorola的6800接口,本系统中采用STM32高速的IO口模拟8080接口时序。综上所述,选用的TFT液晶必须满足两个条件,第一,带有独立的显存。第二,带有8080接口。设计中采用了台湾采用晶彩光电的AM240320TFT液晶屏,它的主控制芯片为ILI9320,自带总大小为172820(24Ox320x18/8)的显存,模块的16位数据线与显寸的对应关系为565方式,它支持包括8080接口在内多种控制输入信号。

STM32采用外部8MHz的晶振作为输入时钟,内部锁相环将时钟倍频到72MHz作为系统时钟,采用GPIO口模拟8080时序并行驱动2.8寸TFT屏,显示部分的处理器和液晶显示器的硬件电路接口电路如图2所示。

基于STM32的高性能低功耗人机界面系统设计
图2 系统液晶接口原理图

2.3、SPI接口Flash存储叠的特点

由于在本系统中整个的汉字字库需要存储在外部Flash中,所以需要选择一种Flash存储芯片,Flash芯片选择需要满足以下要求。第一,尽量占用少的IO口,因为液晶显示器已经采用了并行接口,如果继续选用并行接口的Flash,对芯片的IO消耗较大,这样势必要选用IO更多的芯片,对于便携式设备来说,这是不合理的,所以本系统的设计过程中选用的Flash为SST公司的SST25VF080B,它采用SPI接口,SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,本文中的SPIFlash采用美国SST公司的SST25VF080B芯片,容量为8M位,它工作电压范围为2.7~3.6V,工作在SPI模式0或者模式3,最高工作在50MHz,最小擦除单位为4K字节的扇区,可擦写10万次,数据保持100年以上。而STM32F103RBT6带有高速的硬件SPI接口,可以很方便与SST25VF080B连接通信。所以我们采用SPIFlash来完成对汉字字库的存储,字库存储部分的硬件电路接口图如图3所示。

基于STM32的高性能低功耗人机界面系统设计
图3 SPIFlash接口部分原理图

3、系统软件设计

系统软件包括字库的调用和TFT液晶显示软件设计两个部分,字库调用主要是通过STM32F103RBT6的SPI接口调用存储在SST25VF080B中的中文字库。TFT液晶显示部分主要是通过STM32F103RBT6通用I/O口模拟16位的8080并口,实现对液晶显示器的驱动,在软件设计的过程中需要注意一个问题。就是不同字库编码的标准时不一样的,所以在解码时略有不同,常用的汉字字库有GB2312字库和GBK字库两种。

3.1、GB2312字库和GBK字库

GB2312收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。GB2312—80包含了大部分常用的一、二级汉字,和9区的符号。该字符集是几乎所有的中文系统和国际化的软件都支持的中文字符集,这也是最基本的中文字符集。其编码范围是高位0xa1~0xfe,低位也是0xa1~0xfe;汉字从0xb0a1开始,结束于0xf7fe。GB2312将代码表分为94个区,对应第一字节(0xa1~0xfe);每个区94个位(0xa1~0xfe),对应第二字节,两个字节的值分别为区号值和位号值加32(20H),因此也称为区位码。01~09区为符号、数字区,16~87区为汉字区(0xb0~0xf7),10~15区、88~94区是有待进一步标准化的空白区。GB2312将收录的汉字分成两级:第一级是常用汉字计3755个,置于16~55区,按汉语拼音字母/笔形顺序排列:第二级汉字是次常用汉字计3008个,置于56~87区,按部首/笔画顺序排列。故而GB2312最多能表示6763个汉字。

而GBK内码完全兼容GB2312,同时支持繁体字,总汉字数有2万多个,编码格式如下,每个GBK码由2个字节组成,第一个字节为0X81~0XFE,第二个字节分为两部分,一是0X40~0X7E,二是0X80~0XFE。其中与GB2312相同的区域,字完全相同。把第一个字节代表的意义称为区,那么GBK里面总共有126个区(0XFE~0X81+1),每个区内有190个汉字(0XFE~0X80+0X7E~0X40+2),总共就有126x190=23940个汉字。点阵库只要按照这个编码规则从0X8140开始,逐一建立,每个区的点阵大小为每个汉字所用的字节数乘以190。

这样,就可以得到在这个字库里面定位汉字的方法:

当GBKL《0X7F时:Hp=((GBKH-0x81)&TImes;190+GBKL-0X40)&TImes;(sizex2);

当GBKL》0X80时:Hp=((GBKH-0x81)&TImes;190+GBKL-0X41)&TImes;(sizex2);

其中GBKH、GBKLL分别代表GBK的第一个字节和第二个字节(也就是高位和低位),size代表汉字字体的大小(比如16字体,12字体等),Hp则为对应汉字点阵数据在字库里面的起始地址。

3.2、系统软件流程

对于GBK字库和GB2312字库,他们的解码部分部分略有不同,这个区别主要是由于他们的编码方式不同引起的,对于GBK字库,解码的方式如下:

  qh=*code;
  ql=*(++code);
  if(ql《0x7f)
  ql-=0x40;
  else
  ql-=0x41;
  qh-=0x81;
  foffset=((unsignedlong)190*qh+ql)*(size*2);//得到字库中的字节偏移量
  对于GB2312字库,解码的方式如下:
  qh=*code;
  ql=*(++code);
  ql-=0xa1;
  qh-=0xa1;
  foffset=((unsignedlong)94*qh+ql)*(size*2);//得到字库中的字节偏移量

其中qh、ql分别代表GBK的第一个字节和第二个字节(也就是高位和低位),size代表汉字字体的大小(比如16字体,12字体等),foffset则为对应汉字点阵数据在字库里面的起始地址。

系统启动以后,首先完成时钟的初始化,采用外部8MHz的晶振作为输入时钟,内部锁相环将时钟倍频到72MHz作为系统时钟,完成GPIO的初始化,作为LCD驱动IO的通用IO口的时钟设置为50MHz的推挽模式,接着完成硬件SPI1的初始化,SPI时钟频率设置为18MHz,接着完成液晶的初始化,此过程是通过发送特定的命令序列来实现的,然后刷新显示背景颜色,设置字体颜色,通过上面的程序完成字库中汉字点阵序列的查询,将汉字点阵送液晶屏显示。

系统软件设计的流程图如图4所示。

基于STM32的高性能低功耗人机界面系统设计
图4 汉字显示部分程序流程图

采用方法还不但可以实现标准字体的显示,还可以根据系统要求,采用专用软件生成各种需要的字体,为设计多样性的人机界面系统提供了一种可行的方案。

4、结论

本文根据在全站仪应用于飞机的测量过程中的实际需要,设计了用于测量计算的人机界面系统,在该系统中,采用的处理器内核为ARM最新的Cortex—M3,它基于最新ARMv7架构,采用了至今为止最小的ARM内核,有效地降低了系统功耗。采用SPIFlash来存储汉字字库,通过彩色TFT液晶屏显示,有效地扩展了应用的范围,经过实验验证,本系统的设计方法完全达到设计要求。

来源: eepw.com

围观 388

本文提到的有以下内容:

• 时钟系统与总线矩阵
• SysTick系统定时器
• RTC实时时钟
• 看门狗定时器
• 通用定时器

一、时钟系统与总线矩阵

stm32F4的时钟树如下图所示:

stm32之时钟控制

在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。

HSI是高速内部时钟,RC振荡器,频率为8MHz。
HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
LSI是低速内部时钟,RC振荡器,频率为40kHz。
LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。

我们在学习51单片机的时候,其内部是没有晶振的,而stm32是有的。stm32可以通过RCC(时钟控制寄存器)对时钟进行参数配置以及使能。我们还可以通过修改system_stm32f4xx.c文件,来配置上述时钟树上的一些分频、倍频参数,得到理想的频率。

在单片机系统中,CPU和总线以及外设的时钟设置是非常重要的,因为没有时钟就没有时序,组合电路需要好好理解清楚。我们先来看一下总线矩阵。

stm32之时钟控制

片上总线标准种类繁多,而由ARM公司推出的AMBA片上总线受到了广大IP开发商和SoC系统集成者的青睐,已成为一种流行的工业标

准片上结构。AMBA规范主要包括了AHB(Advanced High performance Bus)系统总线和APB(Advanced Peripheral Bus)外围总线。二者分别适用于高速与相对低速设备的连接。

一般性的时钟设置需要先考虑系统时钟的来源,是内部RC还是外部晶振还是外部的振荡器,是否需要PLL。然后考虑内部总线和外部总线,最后考虑外设的时钟信号。遵从先倍频作为CPU时钟,然后在由内向外分频,下级迁就上级的原则。

二、SysTick系统定时器  

SysTick—系统定时器是属于CM4内核中的一个外设,内嵌在NVIC中。系统定时器是一个24bit的向下递减的计数器,计数器每计数一次的时间为1/SYSCLK,一般我们设置系统时钟SYSCLK等于180M。当重装载数值寄存器的值递减到0的时候,系统定时器就产生一次中断,以此循环往复。

因为SysTick是属于CM4内核的外设,所以所有基于CM4内核的单片机都具有这个系统定时器,使得软件在CM4单片机中可以很容易的移植。

系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。

一般用于系统内部运行以及延时函数。

三、RTC实时时钟

RTC(Real-Time Clock)实时时钟为操作系统提供了一个可靠的时间,并且在断电的情况下,RTC实时时钟也可以通过电池供电,一直运行下去。

RTC通过STRB/LDRB这两个ARM指令向CPU传送8位数据(BCD码)。数据包括秒,分,小时,日期,天,月和年。RTC实时时钟依靠一个外部的32.768Khz的石英晶体,产生周期性的脉冲信号。每一个信号到来时,计数器就加1,通过这种方式,完成计时功能。

RTC实时时钟有如下一些特性:

1,BCD数据:这些数据包括秒、分、小时、日期、、星期几、月和年。
2,闰年产生器
3,报警功能:报警中断或者从掉电模式唤醒
4,解决了千年虫问题 (详见
http://baike.baidu.com/view/9349.htm
5,独立电源引脚RTCVDD
6,支持ms中断作为RTOS内核时钟
7,循环复位(round reset)功能

stm32之时钟控制

如图,RTC实时时钟的框架图,XTIrtc和XTOrtc产生脉冲信号,即外部晶振。传给2^15的一个时钟分频器,得到一个128Hz的频率,这个频率用来产生滴答计数。当时钟计数为0时,产生一个TIME TICK中断信号。时钟控制器用来控制RTC实时时钟的功能。复位寄存器用来重置SEC和MIN寄存器。闰年发生器用来产生闰年逻辑。报警发生器用来控制是否产生报警信号。

四、看门狗定时器

看门狗定时器又分为独立看门狗IWDG和窗口看门狗WWDG。

1、独立看门狗

独立看门狗IWDG其实是一个12位递减计数器,有故障时,计数器减到0,产生复位,无故障时,计数器减到0之前就刷新计数值(喂狗),不进行复位。其采用独立时钟,主要用于监视硬件错误(不受系统时钟影响)。

2、窗口看门狗

窗口看门狗WWDG其实是一个7位递减计数器,有计数上下限,下限位0x40,上限由用户指定,上下限之间刷新计数值则不复位,其他都复位。采用系统时钟,主要用于监视软件错误。

五、通用定时器

stm32的定时器有基本定时器、通用定时器和高级定时器。这里以通用定时器为例,其内部结构如下图所示,需要设置预分频系数,并不是直接使用APB1的时钟。

stm32之时钟控制

通用定时器的计数模式分为5种:

• 向上计数:计数器从0计数到自动装载值。
• 向下计数:从自动装载值计数到0。
• 向上向下计数(中心对齐计数):计数器从0计数到自动装载值,再从自动装载值计数到0,反复循环。
• 输入捕获:测量输入信号的脉宽、PWM波的占空比等。
• 输出比较:PWM波用的就是这种模式。

定时器的时间公式:T=((n-1)*(pre-1))/Tclk,其中n为计数值,pre为预分频系数,Tclk为定时器时钟。

为什么计数值和预分频系数要减一?因为计数是从0开始的,而预分频系数为0时,表示不分频。

定时器用于中断时,注意更新中断标志位。

转自: steed-博客

围观 561

页面

订阅 RSS - STM32