本帖最后由 地瓜patch 于 2024-9-12 22:48 编辑
#申请原创# @21小跑堂
宏晶STC8A8K64S4A12单片机具备多路PWM、多路ADC等功能,适合进行GPIO操作、ADC采样等多种实验。该单片机还具有宽电压工作范围,能够在2.0V到5.5V之间正常工作,便宜且简单易用。已停产。囤货价格上翻10倍且居高不小。对于STC8A8K64S4A12单片机的停产,最直接的影响是现有产品生产的持续性和替换后产品的稳定性。需要寻找替代型号或者改变设计方案,导致开发成本的增加。咨询厂家建议使用STC8A8K64D4单片机替换,引脚pin对pin兼容。程序无需大改,问题是只要有改动,就会涉及到软件的修改、硬件设计的调整以及全面的系统测试以及老化。停车已经是现实,那么只能修改、替换再测试。
在移植前需要有个总体策划,主要包括硬件电路修改和软件移植两个部分。
硬件移植相对简单,主要是根据新单片机的引脚重新布线,核对了STC8A8K64S4A12与STC8A8K64D4两颗单片机果然pin对pin可替换。厂家没说谎;
而软件移植则涉及底层库的替换比如特殊寄存器的修改,接口函数的定义,需要花不少时间;系统时钟一致不用修改;初始化函数修改也需要花不少时间。
主要工作量还是在软件移植方面,我的程序主要涉及串口通信、定时器和IO输入输出控制。下面一步一步来进行移植。 首先 1、替换所引用单片机对应型号的头文件 由#include "STC8xxxx.h"替换为厂家提供的#include "STC8A8K64D4.h" 2、串口移植,以串口1为例进行说明 替换所引用接口对应型号的头文件,更换头文件后编译会出现一系列错误。需要一一改正。 #include "USART.h"替换为厂家提供的#include "STC8A_UART.h" 以串口1为例,需要修改初始化函数将 /******************初始化串口1******************/ void USART1_Init(u32 baudRate) { COMx_InitDefine COMx_InitStructure; //结构定义 COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx COMx_InitStructure.UART_BRT_Use = BRT_Timer2; //使用波特率, 串口1可用BRT_Timer1/BRT_Timer2,串口2固定使用BRT_Timer2,串口3可用BRT_Timer2/BRT_Timer3,串口4可用 BRT_Timer2/BRT_Timer4 COMx_InitStructure.UART_BaudRate = baudRate; //波特率, 一般 110 ~ 115200 COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE COMx_InitStructure.UART_Interrupt = ENABLE; //中断允许, ENABLE或DISABLE COMx_InitStructure.UART_Polity = PolityHigh; //中断优先级, PolityLow,PolityHigh COMx_InitStructure.UART_P_SW = UART1_SW_P30_P31; //切换端口, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17(必须使用内部时钟) COMx_InitStructure.UART_RXD_TXD_Short = DISABLE; //内部短路RXD与TXD, 做中继, ENABLE,DISABLE USART_Configuration(USART1, &COMx_InitStructure); //初始化串口1 USART1,USART2 // PrintString1("USART1 is initialized!\r\n"); //SUART1发送一个字符串
} 编译出错
修改为 void USART1_Init(u32 baudRate) { COMx_InitDefine COMx_InitStructure; //结构定义 COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx COMx_InitStructure.UART_BRT_Use = BRT_Timer2; //使用波特率, 串口1可用BRT_Timer1/BRT_Timer2,串口2固定使用BRT_Timer2,串口3可用BRT_Timer2/BRT_Timer3,串口4可用 BRT_Timer2/BRT_Timer4 COMx_InitStructure.UART_BaudRate = baudRate; //波特率, 一般 110 ~ 115200 COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 USART1,USART2 NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
UART1_SW(UART1_SW_P30_P31); //UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44 // PrintString1("USART1 is initialized!\r\n"); //SUART1发送一个字符串
}
注意,STC8A8K64S4A12与STC8A8K64D4两颗单片机的同名函数和宏定义略有区别修改如下 函数USART_Configuration(); 改为 UART_Configuration(); 接口端口的宏定义由USART1改为 UART1 编译后,会发现提示如下错误 error C202: 'NVIC_UART1_Init': undefined identifier error C202: 'UART1_SW': undefined identifier
这两个函数分别对应两个不同头文件,调用以下头文件 解决该问题。 NVIC_UART1_Init()在#include "STC8A_NVIC.h"中 UART1_SW()在#include "STC8A_Switch.h" 中 编译后提示NULL SUCCESS未定义如下错误,调用 #include "type_def.h" 后 解决。 error C202: 'NULL': undefined identifier error C202: 'SUCCESS': undefined identifier 同时又出现如下错误,提示重复定义,在头文件中注释掉即可。 error C231: 'u8': redefinition error C231: 'u16': redefinition error C231: 'u32': redefinition
这是因为调用#include "type_def.h"文件导致的重复定义,修改后,该错误消失。 3.定时器的移植,以timer0为例 二话不说,先更换头文件 将#include "Timer.h" 更换为#include "STC8A_Timer.h" 编译以下初始化函数会出错 void Timer0_Init(u32 frequency) { TIM_InitTypeDef TIM_InitStructure; //结构定义 TIM_InitStructure.TIM_Mode = TIM_16BitAutoReload; //指定工作模式, TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask TIM_InitStructure.TIM_Polity = PolityLow; //指定中断优先级, PolityHigh,PolityLow TIM_InitStructure.TIM_Interrupt = ENABLE; //中断是否允许, ENABLE或DISABLE TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_12T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext TIM_InitStructure.TIM_ClkOut = DISABLE; //是否输出高速脉冲, ENABLE或DISABLE TIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / (frequency*12)); //初值, TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLE Timer_Inilize(Timer0,&TIM_InitStructure); //初始化Timer0 Timer0,Timer1,Timer2 } 编译出错 error C204: 'TIM_Polity': undefined member error C204: 'TIM_Interrupt': undefined member
将函数中的中断使能和优先级更换为函数NVIC_Timer0_Init() NVIC_Timer0_Init(ENABLE,Priority_0); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3 定时器0初始化函数改为如下 void Timer0_Init(u32 frequency) { TIM_InitTypeDef TIM_InitStructure; //结构定义 TIM_InitStructure.TIM_Mode = TIM_16BitAutoReload; //指定工作模式, TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_12T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext TIM_InitStructure.TIM_ClkOut = DISABLE; //是否输出高速脉冲, ENABLE或DISABLE TIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / (frequency*12)); //初值, TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLE Timer_Inilize(Timer0,&TIM_InitStructure); //初始化Timer0 Timer0,Timer1,Timer2 NVIC_Timer0_Init(ENABLE,Priority_0); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3 }
4,最重要的放在最后,UART所用的IO需要定义 首先调用#include"STC8A_GPIO.h" 将原来的端口定义函数 void GPIO_Init(void) { P_SW2 = 0x80; P1M1 = 0x1C; P1M0 = 0x00; P3M0 = 0x00; P3M1 = 0x02; P3PU = 0x02; P4M1 = 0x10; P4M0 = 0x00; P_SW2 = 0x00; } 修改为以下函数,这一步很重要 voidGPIO_config(void) { GPIO_InitTypeDefGPIO_InitStructure;//结构定义
GPIO_InitStructure.Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;//指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7 GPIO_InitStructure.Mode = GPIO_PullUp;//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP GPIO_Inilize(GPIO_P0,&GPIO_InitStructure);//初始化 } 到这里,移植就基本结束了,编译成功,没有错误,下载到新的芯片中,运行正常。
小结: 在STC8A8K64S4A12中用到的接口、功能等,都需要进行修改移植为STC8A8K64D4对应的头文件,然后修改对应的函数调用。 在我的程序中用到了串口通信、定时器和IO输入输出控制,调用UART、TIMER、IO对应的头文件。修改的这些功能对应的函数。
在移植中出现的问题,请回帖留言讨论。
|
无论是否停产,二姨都认为换芯片最好重新写代码。号称的pin to pin,代码直接烧录不是可取之道。作者虽然是被迫重构项目,但是项目修改的过程描述的很是清晰,虽然每个人因为所用外设不同,修改位置不同,但是一通百通。
感谢分享