一 、 环境
- Win10 64位
- Keil
- stm32f103c8
二、 STM32使用
具体请参见我的上一篇博客
三、 连线图
四、 配置串口的输入输出
由于串口的传输是根据中断模式完成的,类似于上一个实验GPIO按钮的中断,于是我们需要实现串口的中断监听。
这里我犯了一个很低级的错误导致了开始时始终无法通过stm32的tx口把数据传输到电脑。
原因是stm32f1xx_hal_msp.c中没有对tx口进行input模式的初始化
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
接下来。
我们需要在main函数里写一个处理串口中断的函数
void USART1_IRQHandler(void)
{
//deal with interrupt
HAL_UART_IRQHandler(&huart1);
}
在void MX_USART1_UART_Init(void) 的串口初始化函数里加入如下语句,开启串口的中断。
__HAL_UART_ENABLE(&huart1);
HAL_NVIC_SetPriority(USART1_IRQn,0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
然后加入下面这条语句,保证初始化时进入中断读取一次,将stm32板子上rx口的输入字符读入到指针c所指向的内存中,这里我们直接采用了一个数组c[2],定义为全局变量。
HAL_UART_Receive_IT(&huart1, (uint8_t*)c, 1);
下面是main函数中重要的全局变量
char c[1]; //串口接收到的字符的缓冲区
int flag = 0; //条件变量,控制main函数中循环的阻塞
char cmd[100]; //命令缓冲区
char test[100]; //提示信息字符串(测试用的地址和长度)
char *temp = cmd; // 指向cmd字符数组的指针
int count=0; //命令的字符数
当中断被检测到时我们进入下面这个函数,也是定义在main函数中的。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
if(temp<=cmd+CMD_LENGTH) //检测temp指针是否超过范围(temp指针开始指向cmd数组的基地址,cmd数组存放用户输入的指令)
{
count++; //记录用户输入串的长度
if(*c=='\r') // 如果是回车
{
*temp = '\0'; //将字符串结束符写入cmd字符数组
printString("\r\nYour command:"); //向串口输出该字符串
printString(cmd); //这里是为了验证输入是否写入了cmd数组
printString("\r\n");
flag = 1; //flag=0时,main函数里的while循环被阻塞
temp = cmd; //输入完一行后将temp指针重新指回cmd数组基址
count = 0; //将count置为0
}
else
{
*temp = *c; // 将该字符写入cmd数组
printChar(*temp); //串口输出给PC端该字符
temp++; //指针移向下一个地址
}
}
else
printString("Length of Command out of bound!\r\n");
HAL_UART_Receive_IT(UartHandle, (uint8_t*)c, 1); //每次处理结束后重新开始receive下一个字符到c缓冲区
}
五、 PEEK&POKE
- SHELL
void exec(void)
{
char *word[100]={NULL};// 从命令中解析出来的单词数组
char s[100]; //
char *p = cmd;
int i = 0;
int addr=0; //PEEK和POKE的地址
int data=0; //对应地址的一个字的数据
word[i] = p;
while(*p!=0)//将命令解析到word数组中
{
if(*p==' ')
{
*p = '\0';
i++;
word[i] = p+1;
}
p++;
}
i=0;
while(word[i]!=0) //打印单词是否正确地被解析
{
printString(word[i]);
printString("\r\n");
i++;
}
if(i>3||i<=1) //如果单词数不是2或3 则命令错误
printString("Error number of args\r\n");
else
{
if(i==2) //应该是PEEK命令
if(strcmp(word[0],"peek")==0)
{
sscanf(word[1],"%x",&addr); //将peek后的地址按%x格式输出到addr
sprintf(s,"PEEK @%x --> %x\r\n",addr,*((int*)addr)); //按格式打印到字符串s
printString(s);串口输出s
}
else //如果不是输出指令类型错误
printString("wrong type\r\n");
else if(i==3)//应该是POKE命令
{
if(strcmp(word[0],"poke")==0)
{
sscanf(word[1],"%x",&addr);
sscanf(word[2],"%x",&data);
*((int*)addr) = data; 将地址对应的字写为data
sprintf(s,"POKE @%x --> %x\r\n",addr,*((int*)addr));
printString(s);
}
else //如果不是POKE命令输出错误
printString("wrong type\r\n");
}
}
}
- 结果