目录:
USB转TTL串口
串口助手, 密码:07z7
stm32有丰富的通讯外设,USART(Universal Synchronous Asynchronous Receiver Transmitter)、SPI(Serial Peripheral interface)、I2c(Inter-Integrated Circuit)、CAN(Controller Area Network),因为stm32有完整的且强大的固件库,这使得配置串口的难度大大降低了,和用软件IO口模拟通信时序相比,硬件的支持可以大大提高通信的速率、大大降低出错的概率,从而提高了通信的质量和效率。用IO口模拟USART难度较大,它对延时要求比较苛刻,且出错的概率较大,所以一般很少用IO口模拟USART。IO口模拟I2c比较常见,由于I2c的最高通信速度只有3.4M/s,单片机的IO口速度可以完美驾驭。由于SPI多用于一些较高速的通信,例如LCD、OLED、TFT显示器的写入,EEPROM (Electrically Erasable Programmable read only memory)的写入和读取,用IO口模拟效果不是很理想,所以建议使用硬件自带接口。
通过对stm32几个模块的操作,我们可以发现stm32外设配置的一些基本套路:打开相应的时钟->配置相应的引脚功能->声明对应的结构体->利用相应的Init函数进行初始化
打开打开USATT1、GPIOA、AFIO的时钟
void usart_config()
{
/*打开USATT1、GPIOA、AFIO的时钟*/
RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 \
| RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
/*配置对应的串口引脚*/
usart_release_gpio_init();
/*配置串口中断*/
usart_para_config();
USART_ClearFlag(USART1,USART_FLAG_TC); //清除发送完成标志位
NVIC_Config(); //初始化NVIO
USART_Cmd(USART1, ENABLE); //使能串口1
}
void usart_release_gpio_init()
{
GPIO_InitTypeDef GPIO_InitStruct;
/*配置PA9为复用推外输出*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/*配置PA10为浮空输入*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
配置NVIC(Nested Vectored Interrupt Controller),即内嵌向量中断控制器,它是用来配置中断抢占优先级和从优先级(响应优先级)的
关于抢占优先级和响应优先级区别:
高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。
抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure; //NVIC 初始化结构体声明
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //设置串口1 中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
NVIC_Init(&NVIC_InitStructure);
}
void usart_para_config(void)
{
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = 115200;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;//8
USART_InitStruct.USART_Parity = USART_Parity_No; //N
USART_InitStruct.USART_StopBits = USART_StopBits_1; //1
USART_Init(USART1, &USART_InitStruct);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能接收中断
}
USART_SendData(USART1, 0x08);
这个函数就能够完成单字节的发送了#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "timer.h"
#include "usart.h"
int main()
{
SystemInit(); //初始化系统,系统时钟设定为72MHz
systick_init(72); //配置systick,中断时间设置为72000/72000000 = 1us
usart_config();
while(1)
{
USART_SendData(USART1, 0x08);
delay_ms(100);
}
}
typedef struct
{
u8 head;
u8 tail;
u8 direction;
u8 data[4];
}send_stack;
send_stack tx_stack;
void tx_stack_init()
{
tx_stack.head = 0xaa; //协议栈头,起始位,1010 1010b
tx_stack.direction = 0x09;//数据流方向,0x09表示从单片机发出
memset(tx_stack.data, 0, sizeof(tx_stack.data));//把tx_stack.data[]全部初始化为零
tx_stack.tail = 0xdd; //协议栈尾,结束位,1101 1101b,栈头和栈尾最好能互补
}
void usart_senddata()
{
u8 i;
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, tx_stack.head);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, tx_stack.direction);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
for(i = 0; i < 4; i++)
{
USART_SendData(USART1, tx_stack.data[i]);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
USART_SendData(USART1, tx_stack.tail);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
typedef struct
{
u8 head;
u8 tail;
u8 direction;
u8 data[4];
u8 lock_flag;
u8 data_pt;
}receive_stack;
receive_stack rx_stack;
void rx_stack_init()
{
rx_stack.head = 0x00; //协议栈头,起始位
rx_stack.direction = 0x00; //数据流方向,0x09表示从单片机发出
memset(rx_stack.data, 0, sizeof(rx_stack.data));//把tx_stack.data[]全部初始化为零
rx_stack.tail = 0x00; //协议栈尾,结束位
rx_stack.data_pt = 0x00;
rx_stack.lock_flag = UNLOCK;
}
void USART1_IRQHandler(void)
{
u8 receive_data;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判断读寄存器是否非空
{
receive_data = USART_ReceiveData(USART1); //接收单个字节的串口数据
if(rx_stack.lock_flag == UNLOCK) //如果接收协议栈未锁柱
{
if(receive_data == 0xaa)
{
rx_stack.head = receive_data;
}
else if(receive_data == 0xf9)
{
rx_stack.direction = receive_data;
}
else if(receive_data == 0xdd)
{
rx_stack.tail = receive_data;
if(rx_stack.data_pt >= 4)// && (rx_stack.tail == 0xdd))
{
rx_stack.data_pt = 0;
rx_stack.lock_flag = LOCK;
}
}
else
{
rx_stack.data[rx_stack.data_pt] = receive_data;
rx_stack.data_pt++;
if(rx_stack.data_pt > 4)// && (rx_stack.tail == 0xdd))
{
rx_stack.data_pt = 0;
rx_stack.lock_flag = LOCK;
}
}
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接受中断标志
}
}
void ptr_handle(u8 *stack)
{
u8 *stack_pt;
stack_pt = stack;
if(*stack_pt == 0xff)
{
key0.key_change_bit = CHGE_IN;
if((key0.led_on_off % 2) == 1)
{
}
else
{
key0.led_on_off = key0.led_on_off >=3 ? 0 : key0.led_on_off + 1;
}
}
else
{
key0.key_change_bit = CHGE_IN;
if((key0.led_on_off % 2) == 1)
{
key0.led_on_off = key0.led_on_off >=3 ? 0 : key0.led_on_off + 1;
}
else
{
}
}
stack_pt ++;
if(*stack_pt == 0xff)
{
key1.key_change_bit = CHGE_IN;
if((key1.led_on_off % 2) == 1)
{
}
else
{
key1.led_on_off = key1.led_on_off >=3 ? 0 : key1.led_on_off + 1;
}
}
else
{
key1.key_change_bit = CHGE_IN;
if((key1.led_on_off % 2) == 1)
{
key1.led_on_off = key1.led_on_off >=3 ? 0 : key1.led_on_off + 1;
}
else
{
}
}
stack_pt ++;
if(*stack_pt == 0xff)
{
key2.key_change_bit = CHGE_IN;
if((key2.led_on_off % 2) == 1)
{
}
else
{
key2.led_on_off = key2.led_on_off >=3 ? 0 : key2.led_on_off + 1;
}
}
else
{
key2.key_change_bit = CHGE_IN;
if((key2.led_on_off % 2) == 1)
{
key2.led_on_off = key2.led_on_off >=3 ? 0 : key2.led_on_off + 1;
}
else
{
}
}
stack_pt ++;
if(*stack_pt == 0xff)
{
key3.key_change_bit = CHGE_IN;
if((key3.led_on_off % 2) == 1)
{
}
else
{
key3.led_on_off = key3.led_on_off >=3 ? 0 : key3.led_on_off + 1;
}
}
else
{
key3.key_change_bit = CHGE_IN;
if((key3.led_on_off % 2) == 1)
{
key3.led_on_off = key3.led_on_off >=3 ? 0 : key3.led_on_off + 1;
}
else
{
}
}
rx_stack.lock_flag = UNLOCK;
}
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "timer.h"
#include "gpio_config.h"
#include "usart.h"
int main()
{
SystemInit(); //初始化系统,系统时钟设定为72MHz
systick_init(72); //配置systick,中断时间设置为72000/72000000 = 1us
led_gpio_init();
usart_config();
tx_stack_init();
while(1)
{
if (key0.key_change_bit == CHGE_IN)
{
if((key0.led_on_off % 2) == 1)
{
LED0_ON; //打开LED0
tx_stack.data[0] = 0xff;
}
else
{
LED0_OFF; //关闭LED0
tx_stack.data[0] = 0x00;
}
key0.key_change_bit = NO_CHGE;
}
if (key1.key_change_bit == CHGE_IN)
{
if((key1.led_on_off % 2) == 1)
{
LED1_ON; //打开LED1
tx_stack.data[1] = 0xff;
}
else
{
LED1_OFF; //关闭LED1
tx_stack.data[1] = 0x00;
}
key1.key_change_bit = NO_CHGE;
}
if (key2.key_change_bit == CHGE_IN)
{
if((key2.led_on_off % 2) == 1)
{
LED2_ON; //打开LED2
tx_stack.data[2] = 0xff;
}
else
{
LED2_OFF; //关闭LED2
tx_stack.data[2] = 0x00;
}
key2.key_change_bit = NO_CHGE;
}
if (key3.key_change_bit == CHGE_IN)
{
if((key3.led_on_off % 2) == 1)
{
LED3_ON; //打开LED3
tx_stack.data[3] = 0xff;
}
else
{
LED3_OFF; //关闭LED3
tx_stack.data[3] = 0x00;
}
key3.key_change_bit = NO_CHGE;
usart_senddata();
}
if(rx_stack.lock_flag == LOCK)
{
ptr_handle(rx_stack.data); //运行协议解析函数
}
}
}
使用printf函数,需要包含其头文件stdio.h
,即标准输入输出头文件,std是standard的缩写,是标准的意思;i是input,输入;o是output,输出;h是head,头,头文件的意思。
然后在usart,c中编写字符写入函数,将格式化后的字符串依次写入到发送总线上
int fputc(int ch, FILE *f)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET)
{
}
USART_SendData(USART1, (uint8_t) ch);
return ch;
}
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "timer.h"
#include "usart.h"
int main()
{
SystemInit(); //初始化系统,系统时钟设定为72MHz
systick_init(72); //配置systick,中断时间设置为72000/72000000 = 1us
led_gpio_init();
usart_config();
tx_stack_init();
while(1)
{
printf("Hello World!\n%d\n\n", 12345);
delay_ms(100);
}
}
代码链接
回到顶部