经过一段时间的学习,终于完成了自己的第一个程序开发,好兴奋!给大家分享一下程序。
程序功能:实现普通IO口转串口进行数据传输的功能
开发板型号:STM32F103 mini 版
程序说明:因为开发板串口线接口为PA9和PA10,所以必须借用这两个IO口实现转串口通信(其它IO口开发板上没有和输出口相连);由于刚接触程序开发,所以程序中可能存在很多不规范处,还请大家指正,一起学习。本程序参考了本论坛”贵在坚持“师兄的程序代码,链接http://www.openedv.com/posts/list/26933.htm
接收数据用的方法是通过一个外部中断来判断是否有数据发送过来,如果发生了外部中断在外部中断中启动定时器,
利用定时器延时来读取数据;利用STM32强大的定时器功能,只需一个通用定时器,跟据你的波特率设好定时器参数,但不要开中断,在你需要
模拟串口的引脚开启外部下降沿触发中断,一有中断表示有数据发来,这里开启定时器中断,每一个定时器中断读
这个GPIO口电平,并移位存储,读9次,(第一次是启始位,应抛弃),即是一个接收字节。
注意,下降沿触发中断后立即关掉这个中断,只在一个串口字节完后(收到结束位)再在定时器中断里重开外部中断,
等待下一个要接收的字节到来。
代码如下:
void EXTI10_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //输出,一定不能设置复用功能输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
GPIO_SetBits(GPIOA,GPIO_Pin_9);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入//浮空输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_10); //高电平输入
//GPIOA.10 中断线以及中断初始化配置 下降沿触发
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource10);
EXTI_InitStructure.EXTI_Line=EXTI_Line10;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void EXTI15_10_IRQHandler(void)
{
//delay_us(10);//消抖
//if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_10) == RESET)//PA.10仍为低电平(在发送起始位)
if(EXTI_GetFlagStatus(EXTI_Line10) != RESET) //外部中断标志位置位
{
EXTI->IMR &= ~(EXTI_Line10); //屏蔽外部中断
EXTI_ClearITPendingBit(EXTI_Line10);//清除外部中断标记位
// delayUs(20); //为使后面采样在中间点上增加的延时
TIM_SetCounter(TIM3, 0);
TIM_Cmd(TIM3,ENABLE); //开启TIM3
}
}
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
TIM_TimeBaseStructure.TIM_Period = arr-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc-1; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_ClearITPendingBit(TIM3, TIM_FLAG_Update);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//使能指定TIM3 的更新中断
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_Cmd(TIM3,DISABLE); //关闭TIM3
}
void TIM3_IRQHandler(void)
{
static uint8_t data_temp =0;
uint8_t tmp;
static uint8_t i=0;
tmp=0;
if(TIM_GetFlagStatus(TIM3, TIM_FLAG_Update) != RESET)
{
// delay_us(104);//采样延时,采样中间点
TIM_ClearITPendingBit(TIM3, TIM_FLAG_Update);//清除 TIM3 更新中断待处理位
tmp = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10);
if(tmp == 1)
data_temp |= (1 << i); //数据传输,低位在前
i++;
if(i >= 8)
{
i = 0;
IO_UART_RX_BUF[len++]=data_temp;
data_temp=0; //清除DATA数据
TIM_Cmd(TIM3,DISABLE); //关闭TIM3
if((IO_UART_RX_BUF[len-1]==0x0a)||len>=(IO_UART_REC_LEN))//收到回车符或者接收buff满
{
tx_len=len;//发送的字符数
len=0;//清0,准备下次接收数据
receivedFlag = 1; //接收标志位置位
}
EXTI->IMR |= EXTI_Line10; //开启外部中断
}
}
}
主函数
#include "sys.h"
#include "io_uart.h"
#include "stdio.h"
extern uint8_t DATA1; // DATA1主函数中用于输出的
extern __IO uint8_t receivedFlag; //接受完成标志位
u8 IO_UART_RX_BUF[IO_UART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
u16 IO_UART_RX_STA; //接收状态标记
extern u8 tx_len;
//extern volatile u8 tx_len;
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(int x)
{
x = x;
}
void SendOneByte(u8 Byte)
{
u8 i=8,tmp;
TXD_low(); //发送起始位
delay_us(104);
//发送8位数据
for(i=0;i<8;i++)
{
tmp = (Byte >> i) & 0x01; //低位在前
if(tmp == 0)
{
TXD_low();
delay_us(104); //0
}
else
{
TXD_high();
delay_us(104); //1
}
}
TXD_high();
delay_us(104);
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
SendOneByte((uint8_t) ch);
return ch;
}
#endif
void SendBytes(u8 *str,u8 len) //发送数组最好用这个,也可发送字符串
{
u16 i;
for(i=0;i<len;i++)
{
SendOneByte(str);
}
}
int main(void)
{
delay_init();
EXTI10_Init();
TIM3_Int_Init(104,72);
//delay_ms(100);
while(1)
{
if(receivedFlag==1)
{
// printf("Hellow,your word is: ");
SendBytes(IO_UART_RX_BUF,tx_len);//发送数据
// printf("\n");
receivedFlag=0;
}
}
}
IO_Uart.h头文件
#ifndef __IO_Uart_H
#define __IO_Uart_H
#include "sys.h"
#include "delay.h"
#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_exti.h"
#define IO_UART_REC_LEN 200 //定义最大接收字节数 200
#define TXD_high() GPIO_SetBits(GPIOA, GPIO_Pin_9) //PA.9发送
#define TXD_low() GPIO_ResetBits(GPIOA, GPIO_Pin_9)
extern u8 IO_UART_RX_BUF[IO_UART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 IO_UART_RX_STA; //接收状态标记
static volatile u8 len;
// static volatile u8 tx_len;
void EXTI10_Init(void);
void TIM3_Int_Init(u16 arr,u16 psc);
#endif
|