Lab4 bootloader

实验连接示意图

所用器材列表

硬件

- STM32F103核心板一块
- microUSB线
- STLinkban板和USB串口板

软件

- 交叉编译软件

实验步骤、操作的命令和结果

连接STM32和其他设备

写一个自己的建议bootloader,能通过串口执行两条最简单的指令:

  1. peek addr以一个字为单位读取内存中addr位置的数据,并以十六进制的形式输出
  2. poke addr data以一个字为单位修改内存中addr位置的数据为data

    源代码

    输入输出接口

1
// 串口输出单个字符
void myPutc(char ch) {
    HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,100);
}
// 串口输出字符串
void myPuts(char *str) {
for (int i = 0; i < strlen(str); i++)
  myPutc(str[i]);
}
// 串口读取单个字符(时限time_bound)
int8_t myGetc(uint8_t *c, uint16_t time_bound) {
while (time_bound) {  // 时限控制
  if (uart_rev.front != uart_rev.rear) {
*c = *uart_rev.front;
uart_rev.front++;
if (uart_rev.front >= buf + BUFSIZE)  // 下标控制
  uart_rev.front = buf;
return 0;
  }
  time_bound--;
}
return (int8_t) – 1;
}
// 串口读取字符串
int8_t myGets(uint8_t *str, uint16_t bound) {
int count = 0;
bound--;
while (count < bound) {
  if (uart_rev.front != uart_rev.rear) {
    char ch = *uart_rev.front;
    uart_rev.front++;
    if (uart_rev.front > buf + BUFSIZE)
      uart_rev.front = buf;
    if (ch == '\r')  // 处理换行
      break;
      *str = ch;
    if (ch != ' ') {  // 非空有效
      str++;
      count++;
    }
  }
}
*str = '\0';
return count;
}

中断处理

1
void HAL_UART_RxCpltCallback(UART_HandleTypeDef  *UartHandle) 
{
  uint8_t ret = HAL_OK;
    char ch = *uart_rev.rear;
    myPutc(ch);
    if (c == '\r')  // 回车补’\n’
        myPutc('\n');
    
    // 移动buf指针
    uart_rev.rear++;
    if (uart_rev.rear > buf + BUFSIZE)
      uart_rev.rear = buf;
    if (uart_rev.rear == uart_rev.front) {
        uart_rev.front++;
    	 if (uart_rev.front > buf + BUFSIZE)
     		uart_rev.front = buf;
    }
    do{  
       }while(HAL_UART_Receive_IT(UartHandle, uart_rev.rear, 1) != HAL_OK);
}
         void USART1_IRQHandler(void){
    //调用HAL函数库自带的处理函数
    HAL_UART_IRQHandler(&huart1);
}

命令处理

while (1) {
  char cmd[MAXLEN];
  char s2[MAXLEN];
  count = 0;
  myPuts("Please input your instruction: ");
  count = myGets((uint8_t*)s1, MAXLEN); // 获取输入
  sscanf(s1, "%s", cmd);
  if (strcmp(cmd, "peek") == 0) { // “peek”命令
int addr;
int res = sscanf(s1 + PEEKLEN, “%x %s”, &addr, s2);
if (res == 1) {
  sprintf(s2, "peek: %x %x\r\n, addr, *((int *)addr)");
  myPuts(s2);  // 输出结果
}
else myPuts("error\r\n");
  }
  else if (strcmp(cmd, "poke") == 0) {
int addr, data;
int res = sscanf(str + POKELEN, "%x %x %s", &addr, &data, s);  
if (res == 2) {
  *((int *)addr) = data; // 写入数据
  sprintf(s2, "poke: %x %x\r\n", addr, *((int *)addr));
  myPuts(s2); 
}
else myPuts("error\r\n");  // 出错
  }
           else myPuts("error\r\n");   // 非peek或poke命令
}

结果与分析

poke命令执行完之后,peek对应地址能得到正确的数据,符合实验预期。