首页 » 通讯 » STC8A运用心得_函数_除法

STC8A运用心得_函数_除法

少女玫瑰心 2025-01-20 15:16:32 0

扫一扫用手机浏览

文章目录 [+]

stm32f103c8与stc8a8k64d4比拟紧张资源比拟

STC8A运用心得_函数_除法 STC8A运用心得_函数_除法 通讯

STM32F103V8

STC8A运用心得_函数_除法 STC8A运用心得_函数_除法 通讯
(图片来自网络侵删)

STC8A8K64D4

GPIO

37pin

43pin

主频

72M

45M

flash

64K

64K

RAM

20K

8K

UART

3

4

ADC

10 ch,10位

15ch, 12位

定时器

1tick + 4个32位

4个

乘除法指令

单周期硬件乘除法

价格

64元

4.5元

最主要的是: STC有现货

   针对stc8a8k64d4的硬件资源,由于其没有硬件乘除法,导致其在须要进行大量数据打算的运用处景上效率低下,对付一样平常的运用处景,stc在硬件资源上完备够用,在现有的供应链条件下,STC是一个非常不错的选择。

  俗话说有利就有弊,STC带来了不少的硬件本钱上风,但是其在编程上却带来了一些不适应,我们在代码编写时,须要特殊把稳。

  由于stc系列单片机是基于51架构,虽然它在内核上进行了加强,但是由于时期的局限性,51架构和当代的MCU架构比较,存在不少的差距。
由于当代编译器不断的演进,我们大部人都是利用C措辞进行编程,这在一定程度上,帮助我们屏蔽了架构层面的巨大差异。
而且由于架构的掉队,再加宏晶公司与ST公司本身在IP上面的技能差距,这导致我们在利用STC51的外设时,也有很大的差异。
下图是51的架构和stm32的架构,可以看出明显的差距。

编程模型的差异 -- 函数重入

  对付C措辞的编程模型(请参看我前面的文章《C措辞代码组成 - BSS、Data、Stack、Heap、Code、Const》),51和ARM在处理stack上,有巨大的差异。
51加架构中,sp指针指向的区域是pdata区域,这个区域最大情形只有256个字节,作为栈来说,是不可能用来分配局部变量的。
因此keil编译器对付临时变量,采取了一种叫作变量覆盖的技能,即多个函数利用同一区域作作为临时变量区,下一个函数调用运行时,会将上一个函数运行的临时变量覆盖掉。
这样就办理了栈空间不敷的问题。
而且由于没有进出栈的操作,也提高了代码效率。
但这带来的最大的问题便是函数重入问题,即51代码全部是不可重入的,如果一个函数在中断中被调用,那就意味着这个函数必须是可重入的,才能正常运行,而且这个中断函数所调用的下级函数也必须是可重入的。
如何办理重入问题:

keil通过仿照堆栈技能,可以实现函数的重入,通过增加关键字 reentrant 将一个函数定义为可重入函数;将须要重入的函数定义为原子操作,即进入该函数时,禁止全局中断,实行完成后,开启全局中断;中断函数中不调用其它函数,只是置标志,进行变量操作,然后再在main的主循环中查询标志,再实行相应的操作;

以上三种方法,各有缺点,方法一大略粗爆,须要花费更多的资源;方法二会导致中断相应不及时;方法三导致中断相应不及时。
以是用户须要根据项目特点,利用得当的策略;

函数传参

  C51通过寄存器通报参数,最多只能通报三个参数

对付三个或者三个以内的参数,利用寄存器传参;对付多于三个的参数,可以定义为xdata变量进行传参;将函数定义为可重入函数利用栈进行传参数;

乘除法

  由于51没有硬件乘除法,而且是8位机,对付除法指令,十分耗时,这会导致程序相应慢。
对付除法指令,只管即便利用移位操作来代替。

调试问题

  STC51是没有像arm那样的jtag调试接口,下载程序和调试是通过串口进行的,但是在利用串口进行单步调试时,非常不稳定,常常通讯不上,导致调试失落败。
在实际项目中,我是利用uart打印log来进行调试。
由于打印的字符串是定义在常量区,过多的打印会导致代码量增大,以是要合理的利用打印。

串口驱动优化

  由于STC51的串口只有发送完成中断和接管完成中断,而没有接管空闲中断,这就须要我们利用分外的处理办法,详细方法可以拜会我前面的文章《串口吸收中的帧同步》。
代码如下

//收发数据的数据构造typedef struct{ u8 id; //串口号 u8 TX_read; //发送读指针 u8 TX_write; //发送写指针 u8 B_TX_busy; //忙标志 u8 RX_Cnt; //吸收字节计数 u8 RX_TimeOut; //吸收超时 u8 B_RX_OK; //吸收块完成} COMx_Define; u8 xdata TX1_Buffer[COM_TX1_Lenth]; //发送缓冲u8 xdata RX1_Buffer[COM_RX1_Lenth]; //吸收缓冲//定时器中断//用来判断帧超时, 在1ms中断中调用void Serial_HookMs(void){ if(COM1.RX_TimeOut > 0){ COM1.RX_TimeOut --; } else { //if(COM1.RX_Cnt > 0){ //COM1.B_RX_OK = 1; //} }}//中断函数,发送中断和接管中断void UART1_ISR_Handler (void) interrupt UART1_VECTOR{ if(RI){ RI = 0; if(COM1.RX_Cnt >= COM_RX1_Lenth) COM1.RX_Cnt = 0; RX1_Buffer[COM1.RX_Cnt++] = SBUF; COM1.RX_TimeOut = TimeOutSet1; } if(TI){ TI = 0; if(COM1.TX_read != COM1.TX_write){ SBUF = TX1_Buffer[COM1.TX_read]; if(++COM1.TX_read >= COM_TX1_Lenth) COM1.TX_read = 0; } else COM1.B_TX_busy = 0; }}int Serial_Read(UART_Port_t port, uint8_t pmsg, int msg_size){ COMx_Define com = NULL; int len = 0; uint8_t rbuff = NULL; switch(port){ case UART1: com = &COM1; rbuff = RX1_Buffer; break; default: return -1; } if((com->RX_TimeOut == 0) && (com->RX_Cnt > 0)){ if(msg_size < com->RX_Cnt){ return -2; } len = com->RX_Cnt; memcpy(pmsg, rbuff, len); com->RX_Cnt = 0; return len; } return -3;}//采取中断发送int Serial_Write(UART_Port_t port, uint8_t pmsg, int len){ COMx_Define com = NULL; uint8_t sbuff = NULL; int i; int s_buff_max = 0; void ( uart_send)(u8 dat); switch(port){ case UART1: com = &COM1; sbuff = TX1_Buffer; uart_send = TX1_write2buff; s_buff_max = COM_TX1_Lenth; break; default: return -1; } if(com->B_TX_busy != 0){ //发送中 return -2; } //剩余空间不足 if((s_buff_max - (com->TX_write + s_buff_max - com->TX_read) % s_buff_max) < len){ return -3; } //将数据考贝到缓冲区中; for(i = 1; i < len; i ++){ sbuff[com->TX_write] = pmsg[i]; com->TX_write ++; com->TX_write %= s_buff_max; } uart_send(pmsg[0]); return len;}

利用串口的收发中断以避免壅塞式的收发,用定时器实现帧间隔判断来判断是否是完全一帧,这样极大的增加了程序的效率。

IIC驱动库的坑

  在项目中,利用STC8A的IIC操作外设时,新焊接的板子,会涌现不断复位重启的征象,通过加打印定位程序是卡去世在iic操作中,通过剖析程序,在iic的驱动中存在等应答的操作,这是一个去世循环,如下:

void Wait(void){ while (!(I2CMSST & 0x40)); I2CMSST &= ~0x40;}

  由于新焊接的板子,存在虚焊的问题,导到IIC应答失落败,这就使IIC永久 收不到应答,从而去世在wait中,看门狗无法喂狗,导致复位。
将驱动改为如下:

void Wait(void){ u32 i = 0; while (!(I2CMSST & 0x40)){ i ++; if(i > 250){ break; } } I2CMSST &= ~0x40;}

通过增加超机遇制,来避免永久无法应答的问题。

ADC的坑

  在项目中,利用ADC采集变送器的电压旗子暗记,当ADC采集到的值大于某个值时,输出开关旗子暗记,实际中,ADC采集是在主循环中做的,主循环约为1ms,当溘然接入电压旗子暗记时,差不多要3~4ms,才会输出开关旗子暗记,存在很大的时延。
按理来说,时延该当在一个循环周期以内,即1ms以内才是正常的。
而通过通讯口读取出来的稳定值是精确的。
末了通过打印ADC转换值,才创造ADC的值是有一个较缓的上升过程,这是由于ADC的输入电阻和采样电容较大导致的,详细的请参看前面的文章《AD转换中的采样电容和输入电阻》。
纵然通过调度参数,增加采样韶光,依然无法办理此问题,末了办理的办法是连续多次转换(多次测试后为4次),取末了一次的结果作为效值,从而办理此问题。

数据类型

  由于C51是8位单片机,其数据类型长度与ARM比较还是很大差异的,比如int在keil c51中,默认是 16位的。
如果在调用外部第三方库时,稍不把稳,很随意马虎涌现数据溢出。
详细的可以参看stc8a库中的type_def.h文件。

  由于STC51的外设功能相对大略,而且STC的示例完成度很高,利用起来还是很方便,从32位机转到51,在前期会有一个磨合的过程,由于编译器的缺点提示功能的强大,再加上网上资源的丰富,一样平常的问题,基本都能很快办理。
总的来说,对付一些适宜的运用处景,STC的51单片机是个不错的选择。

标签:

相关文章