stm8源码
A. STM8是红外通讯的绝配
有读者私信我,要获得更详细的内情。很抱歉,因为时间实在有限,而且对于实际场景不了解,所以,简单地更新,添加了点儿内容。至于更加详细的电路图和源码需要额外时间继续补充。
最近使用STM8L152做产品,需要基于红外线通讯的Bootloader。发现STM8L05X/15X是红外通讯的绝配。
红外线大致有CIR和SIR两种。前者主要用于5~10米距离的红外遥控器,采用38kHz载波,有大量的廉价接收解码器可用。后者是IrDa标准之一,曾经是功能手机和笔记本电脑的标准配置,其堆栈和配置实体设计与蓝牙比较像,物理层采用3/16载波方式,需要单独的收发模块。
电子、DVD、机顶盒、空调等传统消费电子中常见的遥控器,我们称之为CIR, Consumer Infra Red。CIR通常使用980nm红外线,还需要采用38KHz~40KHz载波以避免可见光干扰。CIR需要编码和解码电路。
我们可以找到若干编码电路。如果由MCU来实现,则需要产生38~40KHz 载波,另外根据特定的红外遥控协议,如SONY/Philips RC5等产生二进制码流。并利用逻辑门或者三极管来实现二进制码流对于载波的调制。理论上,二进制码流和载波还有一定的时序关系,但是实践下来,这种时序关系的容错率很高。
至于CIR的红外接收部分,因为产量比较大,有低成本模块供应,内置38~40KHz载波发生器,并直接输出解调后的二进制码流。所以解码接收部分任意MCU都可以实现。
综上所述,STM8L的CIR方案中,主要考虑的是编码发射端。
MCU产生38KHz载波最常见的方法是使用定时器。包括设定38KHz的中断,并在中断中去切换GPIO引脚。或者设定一个占空比为50%的PWM中断。其道理是类似的。同时,由软件或者另外一种定时器来产生定时中断,产生二进制码流。两者在外部使用CIR二极管相连,当两个GPIO压差为VCC时,IR二极管点亮,压差为零时,IR二极管关闭。这样就形成了最简单的CIR遥控器。
对于STM8L来说,其内部的低频RC振荡器频率正好在38KHz,当然有些误差,但是对于CIR来说要求没有那么严格。由于是内部IRC,所以并不需要使用定时器来产生中断。
通常38kHz载波采用定时器产生PWM。但是Bootloader状态下必须关闭所有中断。这就限制了许多MCU在这种状态的使用。有部分设计只用了单向传输,但是这种方式试错成本太高了。
STM8L05X内部低速RC就是38kHz。而且可以从引脚引出来为载波,实测37.2kHz。配合USART可以直接构成双向红外通讯和遥控器。比STM推荐的IRTM还好用。
消费者红外线技术是单向的:遥控器负责编码和发射红外线,设备负责接收和解码。在某些环境中,比如说水电煤表的自动抄表系统中,则需要建立起双向红外线通道。
红外线和无线电通讯类似,采用半双工通讯方式。所以软件角度必须要确保时序,不要造成双方的通讯冲突。同时硬件上也可以采取一些方法,保证己方在发射时不进行接收,避免自发自收。
由于38KHz载波的存在,其波特率收到限制,我测试过9.6kbps,但是工作在2.4kbps,误码率要少许多。
在Bootloader模式下,USART RXD可以采用polling方式实现,在低速率情况下不会掉数据。
这个其实和STM8无关了,可以参考Arino的红外编码和红外解码库。总的思路是将红外切割成一个个小的时间片,而无需太多考虑RC5/SONY/Toshiba/RCA等不同的红外遥控协议,直接使用一串二进制数据来编码。这也是大多数通用学习型红外遥控器的原理。
具体实现请参考 How to make IR decoder 以及 How to setup an IR remote and receiver on an Arino .
STM8的片内USART外设是支持IRDA SIR收发标准的。这是一种国际标准,早期移动电话和其他数据终端中多采用此类标准,通讯速率较高,可达到115.2kbps。但相对应的,它的红外收发模组成本在20多元人民币,比消费红外模块贵许多。
STM8的原始MCU架构来自意法半导体的ST7,是意法自主开发的内核。这里额外提一下,意法的STR7和ST7不同,是基于ARM7TDMI内核的产品线。STM8在ST7上做了很多改变,与STM32保持了引脚一致性。所以,STM8是一个性价比较高的MCU。
警告
但是STM8的ITC(中断控制)部分却存在着较大的问题。通过仿真器,我觉得和STM8的虚拟存储器以及压栈的先后顺序有关联。在某些极端嵌套中断情况下会导致堆栈溢出,或者一些莫名其妙的问题。具体请留意 STM8 Error Sheet 。
所以STM8在中断设计方面不能够采用过于复杂的嵌套设计,同时需要做些黑盒压力测试。
本文中的某些做法,如利用IRC直接产生38~40KHz载波的方式,可以作为一种思路,在其他MCU中继续使用。比如STM32F030F4 IRC40KHz/LPC812 SCT等。
B. 求 STM8L的modbus程序主机和从机
Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以成工业网络,进行集中监控。
此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。
C. stm8 硬件i2c从机接收程序
首先,iic做从机的程序源码网上比较多,我就不发了,说下调试方法。
相信主机部分已经调试通过了,在这个前提下,楼主的思路是没错的,接收非空,读数据。iic属于一个硬件接口,出问题的时候需要借助示波器,监测每个时候每个数据的波形,同时用JTAG在线调试,分析从机相关寄存器的状态,与自己计算的理论值做对比看是否正确,最终会找到一个出错的地方,看着一堆数据确实会枯燥一些,楼主加油,祝成功~
D. stm8s内部eeprom块读取失败
$pngname = $openid.'.png';
if(imagepng($QR, $pngname)){
imagedestroy($QR);
$qrurl = W_DOMAIN.''.$pngname;
$this->assign('qrcode',$qrurl);
$this->display();
}
E. 求教stm8l将系统时钟切换到外部晶振
首先看一下 STM8S103K3 的时钟结构图,可以帮助你很好的理解。
这里有几个时钟,就是图中标识的时钟,需要弄清楚一下:fHSE: 外部高速晶振时钟,它是由外部晶振产生,大小由外部晶振大小决定,STM8S的外部晶振范围:1-24M,看图中的”HSE OSC 1-24M“。
fHSI:内部RC高速时钟,它是由内部的RC震荡电路产生的,其值16M。但是可以经过后面的分频器分频,四个分频系数可供选择(1,2,4,8)。注:精准度比外部晶振的要稍差一些。
fMASTER:主时钟,它是由HSE 或者 HSI提供时钟,主要功能给外围设备(peripherals,如I2C,SPI,ADC等)提供时钟,还有给CPU提供时钟源。
fCPU:cpu时钟,它是由fMASTER经过分频得到,其作用就是给CPU提供时钟,一个机械周期就是一个fCPU的时钟周期。
下面是时钟的源码部分,可供大家参考。
这里写了四段程序,分别是:使用高速内部时钟(寄存器版)
使用高速内部时钟(库函数版)
使用外部时钟(寄存器版)
使用外部时钟(库函数版)
- /*******************************************************************************
- * Function Name : InitCpuClock.
- * Description : Initial CPU clock, .
- * Input : None.
- * Output : None.
- * Return : None.
- *******************************************************************************/static void InitCpuClock(void)
- {#if 1
- // 寄存器版本 - 使用高速内部时钟
- //Use HSI @8MHZ, div = 2; 8=16/2
- CLK->ECKR &= ~CLK_ECKR_HSEEN; // 失能外时钟
- CLK->CKDIVR &= (uint8_t)(~CLK_CKDIVR_HSIDIV); // 清零内部时钟预分频
- CLK->CKDIVR |= CLK_PRESCALER_HSIDIV2; // 设置内部时钟预分频 2; 具体可以参考数据手册 (reference manual)
- CLK->ICKR |= CLK_ICKR_HSIEN; // 使能内部高速时钟
- while(!(CLK->ICKR&CLK_ICKR_HSIRDY)); // 等待内部高速时钟稳定, 稳定后则内部时钟已经开跑了。 时钟 = 16/2 M#endif#if 0
- // 库函数版本 - 使用内部高速时钟
- //Use HSI @8MHZ, div = 2; 8=16/2
- CLK_HSECmd(DISABLE); // 失能外时钟
- CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV2); // 设置内部时钟预分频 2; 具体可以参考数据手册 (reference manual)
- CLK_HSICmd(ENABLE); // 使能内部高速时钟
- while(!(CLK->ICKR&CLK_ICKR_HSIRDY)); // 等待内部高速时钟稳定, 稳定后则内部时钟已经开跑了。 时钟 = 16/2 M#endif#if 0// 寄存器版本 - 使用外部时钟
- CLK->CKDIVR |= CLK_PRESCALER_CPUDIV1; // CPU 时钟分频 1,CPU时钟 = 外部时钟(即是外部晶振频率)
- CLK->ECKR |= CLK_ECKR_HSEEN; // 允许外部高速振荡器工作
- while(!(CLK->ECKR & CLK_ECKR_HSERDY)); // 等待外部高速振荡器准备好
- CLK->SWCR |= CLK_SWCR_SWEN; // 使能切换
- CLK->SWR = CLK_SOURCE_HSE; // 选择芯片外部的高速振荡器为主时钟
- while(!(CLK->SWCR&CLK_SWCR_SWIF)); // 等待切换成功
- CLK->SWCR &= ~(CLK_SWCR_SWEN|CLK_SWCR_SWIF); // 清除切换标志#endif#if 0// 库函数版本 - 使用外部时钟
- CLK->CKDIVR |= CLK_PRESCALER_CPUDIV1; // CPU 时钟分频 1,CPU时钟 = 外部时钟(即是外部晶振频率)
- CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, // 时钟自动切换模式,注: 参数是自动切换,不然只使用这一个函数是不能切换成功的
- CLK_SOURCE_HSE, // 要切换的时钟(这里是外部时钟)
- DISABLE, // 是否使能切换完成中断(这里失能)
- CLK_CURRENTCLOCKSTATE_ENABLE);// 是否还使能当前时钟(这里选择 关掉当前时钟HSI)
- CLK->SWCR &= ~(CLK_SWCR_SWEN|CLK_SWCR_SWIF); // 清除切换标志#endif}
源码如下,看注释应该就可以了。
F. stm8s103f3p6的afr怎样配置
本文使用的芯片是是stm8s103f3。
以下主要说明配置TIM2通道1为PWM输出的过程。
1.寄存器配置
4位预分频器,计数器的计数频率Fck_cnt=Fck_psc/2^(PSC[3:0])=16M/2^0=16M
那么计数周期为1/16us,也就是说计数器会每隔1/16us计数一次。
TIM2_PSCR=0x00; //分频值=0 16M
自动重装载寄存器,
当自动重装载寄存器=0时,计数器处于阻塞状态,也就是不计数状态,因为当CNTR=ARR时,CNTR就会清零,所以配置时自动重装载寄存器应该大于0。另外自动重装载寄存器的值就是PWM波形的周期,比如ARR=0X0100,PWM的周期为0x0100*1/16=16us,PWM的周期就是16us
TIM2_ARRH=0x01; //自动重装的值 0x0100
TIM2_ARRL=0x00;
捕获/比较使能寄存器,这个寄存器的配置可以选通相应的Tim2通道。
bit5,bit4为ch2配置,bit1,bit0为ch1配置
如果当前OC1为输出通道,则
bit1:OC1低电平有效
bit0:OC1信号被输出到当前引脚上
TIM2_CCER1=bit0|bit1; //low level,OC1
捕获/比较模式寄存器,
bit1,bit0
CC1S[1:0]为捕获/比较选择
00:CC1通道被配置为输出
bit2保留
bit3输出比较预加载使能
0:不使能
1:使能
bit6,bit5,bit4输出比较模式
110:PWM1模式
PWM1和PWM2模式区别
PWM1:CNT<CCR,CH1被激活
PWM2:CNT>CCR,CH1被激活
TIM2_CCMR1=bit3|bit5|bit6; //MODE
捕获/比较寄存器,这个寄存器决定着PWM的占空比。CCR/ARR=PWM的占空比,例如设置为0x0060,那么占空比为0x0060/0x0100=6/16
TIM2_CCR1H=0x00;
TIM2_CCR1L=0x60;
中断使能寄存器,如果需要中断可以在此设置。
bit1:CC1E 捕获/比较1中断使能
0:CC1 中断不使能
1:CC1中断使能
TIM2_IER=0x00; //更新中断使能
控制寄存器,bit0控制计数器的打开和关闭。
bit0,计数器使能
0:不使能
1:使能
TIM2_CR1=bit0; //enable counter
通过逻辑分析仪测试PD4管脚的输出电平,波形图如下所示。
源码如下,
//*******************************************
1 #define bit0 0x01
2 #define bit1 0x02
3 #define bit2 0x04
4 #define bit3 0x08
5 #define bit4 0x10
6 #define bit5 0x20
7 #define bit6 0x40
8 #define bit7 0x80
9
10 void Timer2_Init(void)
11 {
12 CLK_ICKR|=0x01; //开启内部HSI
13 while(!(CLK_ICKR&0x02));//HSI准备就绪
14 CLK_SWR=0xe1; //HSI为主时钟源
15 CLK_CKDIVR=0x00; //HSI,8分频=16M
16 TIM2_PSCR=0x00; //分频值=0 16M
17 TIM2_ARRH=0x01; //自动重装的值 0x0100
18 TIM2_ARRL=0x00;
19 TIM2_CCER1=bit0|bit1; //low level,OC1
20
21 TIM2_CCMR1=bit3|bit5|bit6; //MODE
22 TIM2_CCR1H=0x00;
23 TIM2_CCR1L=0x60;
24 TIM2_IER=0x00; //更新中断使能
25
26 TIM2_CR1=bit0; //enable counter
27 }
28 int main( void )
29 {
30 Timer2_Init();
31 while(1){};
32 }
G. 谁有范红刚写的stm8单片机自学笔记书上的源码啊
这个没有,可以去单片机论坛找找类似的程序。
懂事电子设计 Vgz
H. stm8s003单片机解密能提供完整的源代码吗
解密得不到源代码,得到的都是反汇编后的二进制数字