STM32F103C8T6串口输入控制闪灯快慢及返回数据

本代码会使用寄存器和库函数相结合


要求:一.初始串口,从串口用printf函数输出内

           二.串口输入可控制B0闪灯快慢"SPEED1",快闪1秒闪5次,"SPEED2",1秒闪1次
           三.输入"GOOD" 串口返回“China”,输入“Other”返回“Nippon”


首先建立allfun.c和allfun.h输入存放我们需要用到函数

需要了解stm32硬件的IO规划


目录

一 (1) 首先根据题目要求在allfun.c中初始化串口,用到串口1,TIM2小灯闪烁,中断优先级

二 (1) 我们为了减轻CPU的工作负担,直接用CPU的“小秘书”--DMA来完成串口一系列的计算

三 (1) 最后定义一下初始化函数

四 (1) 主函数里利用数组实现功能

五.最后打开串口进行调试

六.总结


一 (1) 首先根据题目要求在allfun.c中初始化串口,用到串口1,TIM2小灯闪烁,中断优先级

void  NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);  

  //设置优先级分组:先占优先级0位,从优先级4位

  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;        
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;    
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
  NVIC_Init(&NVIC_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;    
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;    
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;    
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
  NVIC_Init(&NVIC_InitStructure);  
}

一 (2) 设置函数 ch通道  PCLK2主频  BOUND波特率  parity奇偶

void uart_init(char ch,unsigned long int pclk2,unsigned long int bound,char parity)
{
 float temp;
 u16 mantissa;
 u16 fraction;
 temp=(float)(pclk2*1000000)/(bound*16);
 mantissa=temp; 
 fraction=(temp-mantissa)*16; 
 mantissa<<=4;
 mantissa+=fraction;
  
 RCC->APB2ENR|=1<<2;   // 端口B开时钟
 RCC->APB2ENR|=1<<14;  //  USART1使能
    
 if (ch==1) {
 GPIOA->CRH&=0xfffff00f;GPIOA->CRH|=0x000004B0;  //引脚输入输出设置
    
 RCC->APB2RSTR|=1<<14;     //复位USART1
 RCC->APB2RSTR&=~(1<<14);  //恢复正常状态
 
 USART1->BRR=mantissa;     //    10,0001,0001,1100  
 if (parity==0) USART1->CR1|=0X211C;     // 使能 中断开 空闲中断  TE  RE   位10开位9,位9 0偶1奇 位8中断开
 if (parity==1) USART1->CR1|=0X371C;     //有校验位12为1即9位 故为3,11
 if (parity==2) USART1->CR1|=0X351C;     // 使能 中断开 空闲中断  TE  RE   位10开位9,位9 0偶1奇 位8中断开
 USART1->CR3|=1<<6;        // DMAR接收使能 
 }

一 (3) 设置函数 重定向输出到串口,接着根据题目要求在我们输入字符时,也会有相应的字符输出,所以需要在allfun.c中加一个printf函数

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{
  assert_param(IS_USART_ALL_PERIPH(USARTx)); // Check the parameters 
  assert_param(IS_USART_DATA(Data)); 
  USARTx->DR = (Data & (uint16_t)0x01FF);    //Transmit Data
}
int fputc(int ch, FILE *f)
{
    USART_SendData(USART1,(uint8_t)ch);
    while((USART1->SR&0x80) == 0)    ;
    return ch;
 }

}

ps:记得在魔术棒里打钩哦

一 (4) 在stm32f10x_it.c写入中断函数USART1和TIM2中断函数

#include "stm32f10x_it.h"
#include <allfun.h>

u16 tim;

void TIM2_IRQHandler(void)
{
  if(TIM2->SR&0X0001)
  { 
   if (tim<5000) tim++;
  }
  TIM2->SR&=~1; 
}

void USART1_IRQHandler(void)
{
  char kkl=0;
  if (USART1->SR&(1<<4))
   {
    DMA1_Channel5->CCR&=~(1<<0);           //关闭DMA通道
    USART1->CR3&=~(1<<6);           //关闭USART1串口的DMA接收
    rf=300-DMA1_Channel5->CNDTR;    
    kkl=USART1->SR;kkl=0;kkl+=USART1->DR;  //读取一下即可清除标志
  }
}

这样,串口的初始化及定义就完成啦 。

二 (1) 我们为了减轻CPU的工作负担,直接用CPU的“小秘书”--DMA来完成串口一系列的计算

void MYDMA_Config(DMA_Channel_TypeDef *DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
  u32 DR_Base;             //做缓冲用,不知道为什么.非要不可
  RCC->AHBENR|=1<<0;       //开启DMA1时钟
  DR_Base=cpar;            //外设地址
  DMA_CHx->CPAR=DR_Base;   //DMA1 外设地址cpar
  DMA_CHx->CMAR=(u32)cmar; //DMA1,存储器地址
  DMA1_MEM_LEN=cndtr;      //保存DMA传输数据量
  DMA_CHx->CNDTR=cndtr;    //DMA1,传输数据量
  DMA_CHx->CCR=0;          //复位
  DMA_CHx->CCR|=0<<4;      //0读外设    1从存储器读
  DMA_CHx->CCR|=1<<5;      //0普通模式  1循环模式
  DMA_CHx->CCR|=0<<6;      //外设地址非增量模式
  DMA_CHx->CCR|=1<<7;      //存储器增量模式
  DMA_CHx->CCR|=0<<8;      //外设数据宽度为8位  9,8位 00 8 01 16 10 32
  DMA_CHx->CCR|=0<<10;     //存储器数据宽度8位 11,10位 同上
  DMA_CHx->CCR|=1<<12;     //中等优先级
  DMA_CHx->CCR|=0<<14;     //0非存储器到存储器模式,1存储器到非存储器模式,
}

void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
  MYDMA_Config(DMA1_Channel5,(u32)&USART1->DR,(u32)buf,300);

  //DMA1通道5,外设为串口1,存储器为SendBuff,长度100.
  DMA_CHx->CCR&=~(1<<0);             //关闭DMA传输
  DMA_CHx->CNDTR=DMA1_MEM_LEN;       //DMA1,传输数据量
  DMA_CHx->CCR|=1<<0;                //开启DMA传输
  USART1->CR3|=1<<6;
}

三 (1) 最后定义一下初始化函数

void init(void)
{
  SystemInit();
  RCC->APB2ENR|=1<<3;
  RCC->APB2ENR|=1<<2;
  GPIOB->CRL&=0X00FFFF00;   
  GPIOB->CRL|=0X330000B3;   
  NVIC_Configuration();

  RCC->APB1ENR|=1<<0;       //tim2 enable
  TIM2->ARR=9;            
  TIM2->PSC=7199;           
  TIM2->DIER|=1<<0;         
  TIM2->DIER|=1<<6;        
  TIM2->CR1|=0x01;     
  tim=0;


  MYDMA_Enable(DMA1_Channel5);
  uart_init(1,72,115200,0);
  MYDMA_Enable(DMA1_Channel5);

ps:记得要在allfun.h中申明,B0进行宏定义

#ifndef __ALLFUN_H
#define __ALLFUN_H

#include <stm32f10x.h>
#include <misc.h>
#include <stdio.h>

void init(void);
void  NVIC_Configuration(void);
void MYDMA_Config(DMA_Channel_TypeDef *DMA_CHx,u32 cpar,u32 cmar,u16 cndtr);
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);
void uart_init(char ch,unsigned long int pclk2,unsigned long int bound,char parity);
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
int fputc(int ch, FILE *f);

extern u16 tim; 
extern char buf[300],rf;


#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))   
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))   
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C   
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C   
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C   
     
#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808   
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08   
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008   
 
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //
#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //
#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //
 

#define led PBout(0) 

#endif

四 (1) 主函数里利用数组实现功能

#include <allfun.h>
#include <string.h>

int main(void)
{
 u16 i,k2;
 
 init();
 while(1)
 {
 if (rf)
        {    
            if (buf[0]=='G'&&buf[1]=='O'&&buf[2]=='O'&&buf[3]=='D')  {led=0;printf("China\r\n");}
            if (buf[0]=='O'&&buf[1]=='T'&&buf[2]=='H'&&buf[3]=='E'&&buf[4]=='R')  {led=1;printf("Nippon\r\n");}
            if (buf[0]=='S'&&buf[1]=='P'&&buf[2]=='E'&&buf[3]=='E'&&buf[4]=='D'&&buf[5]=='1')  {k2=100;printf("SPEED1\r\n");}
            if (buf[0]=='S'&&buf[1]=='P'&&buf[2]=='E'&&buf[3]=='E'&&buf[4]=='D'&&buf[5]=='2')  {k2=500;printf("SPEED2\r\n");}
       
            for(i=0;i<300;i++) buf[i]=0;
            MYDMA_Enable(DMA1_Channel5);
                
    }
        if(tim>=k2)
        {
      tim=0;
            led=!led;
    }
 }     

}
 

五.最后打开串口进行调试

这样我们就完成啦

六.总结

1.DMA设置,接收USART信息

2.USART1串口设置,波特率设置等

3.TIM中断,B0灯闪烁

4.printf串口输入打印

5.初始化函数

6.主函数里写入算法实现其功能

7.打开串口进行调试

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值