仔细读ST支持文档 UM0560,按步骤操作。
程序准备工作:
1.开串口接收中断,发送。
/* ********************************************
UART2 configured as follow:
- BaudRate = 115200 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Receive and transmit enabled
- Receive interrupt
- UART2 Clock disabled
*********************************************/
void Uart_Init(void)
{
UART2_DeInit();
UART2_Init((u32)115200, UART2_WORDLENGTH_8D, UART2_STOPBITS_1,
UART2_PARITY_NO , UART2_SYNCMODE_CLOCK_DISABLE , UART2_MODE_TXRX_ENABLE);
UART2_ITConfig(UART2_IT_RXNE_OR,ENABLE );
UART2_Cmd(ENABLE );
}
void UART2_SendByte(u8 data)
{
/* Loop until the end of transmission */
while ((UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET));
UART2_SendData8((unsigned char)data);
}
/**
* @brief UART2 RX interrupt routine.
* @param None
* @retval None
*/
#define C_UartRxMaxInx 40
uint8_t V_RxDataInx = 0;
uint8_t V_UartEndTime = 0;
uint8_t VT_RxUartData[C_UartRxMaxInx+1] = {0};
uint8_t B_RxFirts = 0;
INTERRUPT_HANDLER(UART2_RX_IRQHandler, 21)
{
/* In order to detect unexpected events during development,
it is recommended to set a breakpoint on the following instruction.
*/
if(SET == UART2_GetITStatus(UART2_IT_RXNE)) //接收到数据中断
{
UART2_ClearITPendingBit(UART2_IT_RXNE);
if(B_RxFirts == 0)
{
B_RxFirts = 1;
V_UartEndTime =0;
V_RxDataInx = 0;
}
if(V_RxDataInx < C_UartRxMaxInx)//接收串口数据,最多接收40字节
{
V_UartEndTime=0;
VT_RxUartData[V_RxDataInx] = UART2_ReceiveData8();
V_RxDataInx++;
}
else
{
V_UartEndTime = 0; //超过缓存了,不在往里面写数
}
}
else if(SET == UART2_GetITStatus(UART2_IT_OR)) //过载错误
{
UART2->SR = UART2->SR;
UART2_ReceiveData8(); //读状态寄存器,读数据寄存器,清除中断标志
}
}
uint8_t B_HaveRxData = 0;
//************************************************************************
void UartRxScan(void)
{
if(B_RxFirts)
{
V_UartEndTime++;
if(V_UartEndTime>10)//大于50ms认为是新的指令来了
{
B_RxFirts = 0; //下次来数据就覆盖
V_UartEndTime = 0;
B_HaveRxData = 1; //接收到真确的UART数据
VT_RxUartData[C_UartRxMaxInx-1]=''; //这个是保护,超过限定值就结束
}
}
}
2.开定时器定时
/*
初始化Timer2,设置1MS中断
*/
void Init_Timer2(void)
{
TIM2_DeInit();
TIM2_TimeBaseInit(TIM2_PRESCALER_16, 999); //1MHz /1000 = 1000 HZ
TIM2_ClearFlag(TIM2_FLAG_UPDATE);
/* Enable update interrupt */
TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);
TIM2_Cmd(ENABLE);
}
定时器中断服务函数,记接收超时,记反馈超时。
接收超时单位是100ms。
uint8_t V_SystemTimeCount = 0;
INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)
{
/* In order to detect unexpected events during development,
it is recommended to set a breakpoint on the following instruction.
*/
TIM2_ClearITPendingBit(TIM2_IT_UPDATE); //clear flag
UartRxScan();
V_SystemTimeCount++;
if(V_SystemTimeCount>10)
{
V_SystemTimeCount=0;
V_WaitResponceTime++;
}
}
/*
* 函数功能:清空接收数组
*/
void F_ClrRxUartData(void)
{
B_RxFirts = 0;
for(u8 i=0;i
{
VT_RxUartData[i] = 0;
}
}
/*
函数功能:等待反馈
输入参数:V_CMD_ADD 命令地址,在接收数据中的位置
Commond 命令
V_OverTime 最大响应时间
输出参数:C_OverTime 超时
C_Success 成功
C_Waiting 等待
**/
uint8_t V_WaitResponceTime = 0;
uint8_t F_WaitResponce(uint8_t V_CMD_ADD,uint8_t Commond,uint8_t V_OverTime)
{
if(V_WaitResponceTime >V_OverTime)
{
return C_OverTime;
}
else if(VT_RxUartData[V_CMD_ADD] == Commond)
{
F_ClrRxUartData();
V_WaitResponceTime = 0;
return C_Success;
}
else
{
return C_Waiting;
}
}
/*
函数功能:等待应答
输入参数:
输出参数:
C_Success 成功
C_Fail 失败
**/
uint8_t F_Wait_ACK(void)
{
V_WaitResponceTime = 0;
while(1)
{
if(C_Success == F_WaitResponce(0,C_ACK,30))
{
UART2_SendByte(C_ACK);
return C_Success;
}
if(C_Success == F_WaitResponce(0,C_NACK,30))
{
return C_Fail;
}
}
}
1.获取命令和版本号
/*
函数功能:获取BootLoader版本号
返回参数:C_Fail 失败
C_Success 成功
注意: 函数执行完,返回成功。接收数组中应该有参数,
0x05、0x13、0x00、0x11、0x21、0x31、0x43
**/
uint8_t F_CheckVersion(void)
{
UART2_SendByte(C_Get);
UART2_SendByte(~C_Get);
if(F_Wait_ACK() == C_Fail) return C_Fail;
UART2_SendByte(C_ACK);//0x05
UART2_SendByte(C_ACK);//0x13
UART2_SendByte(C_ACK);//0x00
UART2_SendByte(C_ACK);//0x11
UART2_SendByte(C_ACK);//0x21
UART2_SendByte(C_ACK);//0x31
UART2_SendByte(C_ACK);//0x43
if(F_Wait_ACK() == C_Fail) return C_Fail;
return C_Success;
}
写到这里,就能正确获取,指令,版本号。
值得注意的地方是,在支持文档中,要求从机发的所有字节都应该有应答,所以当主机发从机命令,从机发了一个应答,主机应该回一个应答(刚开始我就在这里犯错,没有回应答,造成后面发命令就非应答)。
Reply mode
The host must reply to all the bytes sent from the bootloader.
2.读内存经由UART命令
主机发送给STM8字节如下:
字节1-2: 0x11(命令号) + 0xEE(补码)
字节3-6: 开始地址(32位)
Byte 3 = MSB
Byte 6 = LSB
字节7: 校验和 = XOR (字节3.4.5.6)
字节8: 要读的字节数-1(0 <= N <= 255)
字节9: 校验码(字节8的补码)
注意:要读的字节数-1(0 <= N <= 255),因为数组总是从0开始排序。读超过256个数要重新给地址。
3.擦除内存和写内存命令
在执行这两个操作前要进行写RAM操作,不然直接操作就等不到应答。
参考写RAM链接
通过别人写的文档,发现写入数据才能操作。但实际把数据抄进来,我的这两个操作还是不能正确。之后通过STMFlashLoader Demo.exe 直接用两个串口接收,发现数据是不一样的,可见每一款不同型号的MCU写入的数据都不一样,具体的数据要通过抓取STMFlashLoader Demo.exe和MCU通讯的数据确定。这里注意,执行擦除,写内存,每一次都进行了写RAM,实际操作,写一次就好。
/*
函数功能: Write memory
传入参数: V_SlaveWriteAdress 写入从机的地址
V_SendByteCount 写入多少字节
arr 写入从机的的数组首地址
返回: 成功1,失败0
*/
uint8_t F_ProgramOneBlock(uint32_t V_SlaveWriteAdress,uint8_t V_SendByteCount,uint8_t * arr)
{
uint8_t V_Address1,V_Address2,V_Address3,V_Address4;
UART2_SendByte(C_WriteMemory);
UART2_SendByte(~C_WriteMemory);
if(F_Wait_ACK() == C_Fail) return 0;
V_Address1 = V_Sla
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』