
GPIO控制,不多说,一大堆资料都有,代码不贴了,想希望写成像51那样的P1=0x0F的方法
可以写成GPIO_Write(GPIOE,0x00FF); 这样就可以像51那样用数据来控制IO口的跑马灯了。
51中的循环移位_cror_(a,i) 是一个非常好用的东西,这里可以自己写一段程序,举例一个8位数据
1001 1001 向左移动1位是 01001100,溢出位是1 ,我们把本身这个数据想左移动7位 得到
1000 0000 ,两个数或上,正好是我们要的1100 11 00,可以写出这么一个算法
对于8位数据向右移位 Data>>i|Data<<(7-i) ,如果是16位数据就把7改成16即可。左移算法雷同。
延时明天说了,如今真是又累又没心情了!

STM32 的延时:
在51的时期,我们习惯用循环来做延时这个事情,比较才12M的晶振,指令周期再12分 也就1M,循环个数百次到千次。
但STM32F103 的工作频率是比较高的,建议最高频率达72MHz,当然最高肯定不只72MHz(后面开专题研究超频),而且有些单条指令只占2~3 个时钟周期,速度奇快。
当然我也用循环来做延时8调 delay(1000),里面的K值还贼大,这才出了个有点像1S 的延时。坑爹吧!
死磕的童鞋肯定磕不出什么好办法,作为一届网民,我们还是有利器的,谷歌、度娘。“STM32 延时” 然后新关键词就出现了Systick。多余的我不说了,我不是做教程的也没必要。作为一名工程师要学会的就是自己解决问题,问回来的答案永远不是自己的。
systick 寄存器作用如下
在CTRL寄存器中 有CLKSOURCE这么一控制位,控制的是使用内部时钟或是外部时钟,当初我以为的是使用片外晶振和片内晶振这么一个控制,后来迷惑了,翻看了数遍stm32的时钟关系,发现原来并非这么回事,M3 是STM32的一个内核,时钟控制外设,整片上系统的时钟好比树的主干,而外设是挂在主干上面的各个分支,同样M3 也是,M3使用的是系统主干的系统时钟。而systick 可以有两个时钟一个是和M3 同一个也就是所谓的内部时钟,另一个是系统主干时钟8分频后的外部输入时钟。这也好理解了网上众多教程中所说的要除8的原因。
——————————————————————————————————————
什么??你说你参考网上的教程例子 那个systick 库的程序编译好多错误?当然如果你有一份中文版的STM32 固件库使用手册对照了数百遍也还是没发现那里写错吧。我可以回答你,大哥你真的一句代码都没写错。原因在于你使用的是3.0后的固件库!在网上很多教程中都是写得一个死样的(这里我怀疑曾经有一个高手做出了好的教程,然后后面无数模仿的商家,真实一直被模仿从未被超越。),都是3.0之前的固件库。新的固件库对于systick 有了一个很大的改动。管网中有一份2.0 到3.0固件库升级的说明文档
2.0与3.0固件库对比.pdf
在新固件库下也有一个文档"stm32f10x_stdperiph_lib_um", 搜systick 也可以找到相关的用法,库中给出调用的函数是
if (SysTick_Config (SystemCoreClock / 1000)) ; { /* Setup SysTick for 1 msec interrupts */
while (1);
}
所以延时1ms 我们使用方法是
if (SysTick_Config (SystemCoreClock / 1000))
{ while (1); } //1ms 的延时计数
TimeCount=nCount; // 时间累加
while(TimeCount);
SysTick->CTRL=0x00; // 关闭计数器
SysTick->VAL =0X00; // 清除计数器
另外我们只要在中断函数中加入
void SysTick_Handler(void)
{ TimeCount--; }
延时1S 就是TimeCount=1000,1000个1ms就行了
1ns 的延时就写成 if (SysTick_Config (SystemCoreClock / 1000000))
让倒数值再减少3个0就行了
——————————————————————————————————————
纠结这个库是如何实现的呢,继续近一步分析库函数:
(先去打个水喝)

systick 固件库的函数使用已经从手册中找到了,那么其原理是如何实现的呢?
上面寄存器中,有个重载寄存器RELOAD 满值是0xFFFFFF, 即最大值是16777215, 因为是倒数的,所以倒数72000000 次就是1S 了,当然是在72MHz 系统时钟下使用M3核系统时钟,可是没那么大的框,所以装 72000000/1000=72000 这个数进去就好了,倒数完一次是1ms。
顺着库函数很清楚做的就是SysTick_Config (SystemCoreClock / 1000) 这函数运算。然后跳转导core_cm3.h 这个文件来了,然后看到下面这段代码
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
SysTick->VAL = 0; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
进入函数后第一件事是把输入的变量和SysTick_LOAD_RELOAD_Msk 做了一次比较,这是个什么数呢再跳
#define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */
看到0xFFFFFF 熟悉吧,正是的,RELOAD寄存器能装置的最大值,后面多了个ul? 怎么回事,查了好多资料,基本很少有讲,大致意思是定义的这个数是一个 unsigned long 类型.当我们输入的计数值大于积存能装载的最大值将会返回一个 值为1的错误返回。当然if (SysTick_Config (SystemCoreClock / 1000)) { while (1); } 直接死循环,调试的时候我们就会发现在这个函数跳不出去,因而找到错误。固件库中设置了好多这样的安全关口,保证我们自调试的时候能快速找到问题所在点。
再看载入值 (ticks & SysTick_LOAD_RELOAD_Msk) - 1; 与上一个全F当然出来的是我们填入的数例如72000,但疑问来了,为什么要-1啊~!! 为什么啊~!! 这其实算是一个C 语言的小毛病,Data[5]最大的那个数组是Data[4] 而不是Data[5]吧,是的还有个Data[0] 呢。
剩下的语句基本动作:中断设置、计数器清零、设定控制并且开始,相关寄存器控制位自己看表了。
回头再讲一个差点忘了的东西,我们除了那个除数从来可没给他输入过别的计数值啊。再跳SysTick_Config (SystemCoreClock / 1000) ,SystemCoreClock 跳转到systme_stm32f10x.h后看到uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; 噢,原来这里定义了它等于72MHz,还没到底呢,继续SYSCLK_FREQ_72MHz,再跳
#define SYSCLK_FREQ_72MHz 72000000。结束! 把这些最原始的值代入我们的程序就成了最原始的程序了,所有的计算方法以及寄存器控制灯
今天到此为止,下一章,另类玩转串口,是另类的哦~ 和你们的教程可都不一样的哦。请密切关注,谢谢。THINK YOU

SecureCRT_CN.rar(终端通讯软件,后头有讲)
——————————————————————————————————————————————————————
串口很熟悉了,51中已经非常常见了,用库来做还是非常的容易的,只要简单配置一下就行了
USART_InitTypeDef USART_InitStructure; //定义类型
USART_StructInit(&USART_InitStructure); //初始化数据结构
USART_InitStructure.USART_BaudRate=9600; //波特率选择(可自行增加修改)
USART_Init(USART1,&USART_InitStructure); //配置串口
USART_Cmd(USART1,ENABLE); // 打开串口
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //接收中断
使用也是很简单
发送如下写即可,(u8) ch 为发送的字符数据
USART_SendData(USART1, (u8) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
接收就应该在中断中了,否则这接收会出问题
if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清楚中断标志
Receive_buffer=USART_ReceiveData(USART1);
}
——————————————————————————————————————————————————————
基本的串口通信就如上所做的,当然要想弄点奇偶校验什么的,也配置上去就好了。说点别的吧。
学C的时候大家肯定都学到printf 这个输出吧,是不是和爽~!
printf("很爽有木有,很爽有木有?");
其实单片机也可以用D,这就要时候的时候用上C输出的这个库,并且把printf 这个函数重定义到我们的串口输出去。
这里我们要使用上我们亲爱的stdio.h 库。为此要做以下设置,把Use MicroLIB 钩上
然后 main.c 里写上
#include <stdio.h>
#include <stdarg.h>
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
USART_SendData(USART1, (u8) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return ch;
}
把以上重定义 printf 函数代码打到自己的代码上吧。
printf("Hello,world~!");// 打上经典的一句吧,是不是已经从串口调试助手中出现了???
想打上句中文,貌似有些串口调试助手不支持,这也不够装B 。SO~ 我们需要另外一样工具了“超级终端”。如果你是XP 系统的话,就可以在开始菜单栏里面找到这个东西,设置就自己问度娘吧,其实也就把属性那串口属性设置好就能用了。如果你像我一样是WIN7,噢~ I am sorry,WIN7 把这个工具给阉了。可以找别的中断软件,我这用SecureCRT,上传一个吧~!在顶上呢。(使用方法,自己问谷哥)。
再输入一次,
void LEDUart_Display(u8 LedState)
{
printf("\r\n\n\n\n\n\r*****************************************************************\n\n\r");
printf("----------------STM32 ARM-DIY进程(BRUCEG)-----------------");
printf("\r\n\n\r*****************************************************************\n\n\r");
printf("\r 1.全循环闪烁\n");
printf("\r 2.竖循环闪烁\n");
printf("\r 3.横循环闪烁\n");
printf("\r 4.竖全亮控开关\n");
printf("\r 5.横全亮控开关\n");
printf("\r 6.全亮\n");
printf("\r 7.全灭\n");
printf("\n\r 0.返回上一层\n");
printf("\n\n\r");
printf("\r当前运行状态:%c\n",LedState);
printf("\r请输入控制序号:");
}
然后终端中看~
界面出来咯。这周忙着,得多等一会再传效果图上来了。

LS 那么快占楼来了,呵呵,继续。我现在的进度是比我发帖要快点的,视频嘛我还是觉得我满意的程度再上传吧,自己那关都过不了何必上传呢。
至于我现在模块调得还不多,但相对功能代码量是越来越大了,所以今天破例贴一次完整的代码,至于如何实现解析,看各位自己理解了,基本是结合前面所说的LED循环方法,与串口与电脑通讯的方法用的都是固件库的函数,理解起来还是非常容易的
代码:
#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include <stdio.h>
#include <stdarg.h>
/****************************************************************************/
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
USART_SendData(USART1, (u8) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return ch;
}
/****************************************************************************/
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
u32 TimeCount;
u8 Receive_buffer;
union
{
u8 ALL;
struct
{
u8 Led_F1:1;
u8 Led_F2:1;
u8 Led_F3:1;
u8 Led_F4:1;
u8 Led_F5:1;
u8 Led_F6:1;
u8 Led_F7:1;
u8 Led_F8:1;
}LedFlag;
}LedFlag_State;
/*Private functions-------------------------------------------------------------*/
void RCC_Configuration(void);
void Usart_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void Usart_Display(u8);
void delayms(u32 nCount);
void delayns(u32 nCount);
int main(void)
{
u16 LedData=0x0000;
u8 LedState;
u8 TempState;
u8 i;
TempState=LedState;
RCC_Configuration();
NVIC_Configuration();
Usart_Configuration();
GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);
GPIO_Configuration();
LedFlag_State.ALL=0x00;
Receive_buffer='1';
LedState='1';
GPIO_Write(GPIOE,0xffff);
delayms(1000);
while (1)
{
GPIO_Write(GPIOE,LedData);
delayms(300);
if(TempState!=LedState)
{TempState=LedState;Usart_Display(TempState);delayms(1000);}
switch(LedState)
{
case '1': //十字循环
if(LedFlag_State.LedFlag.Led_F1!=1)
{
LedFlag_State.ALL=0x00;
LedFlag_State.LedFlag.Led_F1=1;
LedData=0xFFFF;
}
else
{
LedData=0x7EEE;
for(i=0;i<4;i++)
{
GPIO_Write(GPIOE,LedData);
delayms(500);
LedData=(LedData>>1|0x8FFF)&(LedData<<1|0xF001);
}
GPIO_Write(GPIOE,0xFFFF);
delayms(300);
LedData=0xE777;
for(i=0;i<4;i++)
{
GPIO_Write(GPIOE,LedData);
delayms(500);
LedData=(LedData<<1|0x1FFF)&(LedData>>1|0xF800);
}
LedData=0xFFFF;
}
break;
/**************************************************************/
case '2': //竖循环
if(LedFlag_State.LedFlag.Led_F2!=1)
{
LedFlag_State.ALL&=0x00;
LedFlag_State.LedFlag.Led_F2=1;
LedData=0xeFeF;
}
else
{
LedData=((LedData>>3)|0xffef)&(LedData<<1|0xff0f)&((LedData>>3)|0xEFFF&(LedData<<1));
}
break;
/**************************************************************/
case '3': //横循环
if(LedFlag_State.LedFlag.Led_F3!=1)
{
LedFlag_State.ALL&=0x00;
LedFlag_State.LedFlag.Led_F3=1;
LedData=0xF7fe;
}
else
{
LedData=((LedData<<1|0xfff0)|((LedData>>3)&0x0001))&((LedData<<3)|0xF7FF)&(LedData>>1|0xf0ff);
}
break;
case '4': //竖控
if(LedFlag_State.LedFlag.Led_F4!=1)
{
LedFlag_State.ALL&=0x00;
LedFlag_State.LedFlag.Led_F4=1;
LedData=0x0F0F;
// Receive_buffer=0x00;
}
else
{
// if(Receive_buffer!=0x00){Receive_buffer=0x00;LedData=~LedData|0x0F0F;}
}
break;
case '5': //横控
if(LedFlag_State.LedFlag.Led_F5!=1)
{
LedFlag_State.ALL&=0x00;
LedFlag_State.LedFlag.Led_F5=1;
LedData=0xF0F0;
// Receive_buffer=0x00;
}
else
{
// if(Receive_buffer!=0x00){Receive_buffer=0x00;LedData=~LedData|0xF0F0;}
}
break;
case '6': //全亮
LedData=0x0000;
break;
case '7': //全灭
LedData=0xFFFF;
break;
default:
if(LedFlag_State.LedFlag.Led_F8!=1)
{
LedFlag_State.ALL&=0x01;
LedFlag_State.LedFlag.Led_F8=1;
printf("\n\n\r输入错误请重新输入!!");
}
else
GPIO_Write(GPIOE,0xFFFF);
break;
}
LedState=Receive_buffer;
}
}
void Usart_Display(u8 LedStatus)
{
printf("\r\n\n\n\n\n\r*****************************************************************\n\n\r");
printf()"\r-------------------------BRUCEG-----------------------------";
printf("\r\n\n\r*****************************************************************\n\n\r");
printf("\r 1.全循环闪烁\n");
printf("\r 2.竖循环闪烁\n");
printf("\r 3.横循环闪烁\n");
printf("\r 4.竖全亮控开关\n");
printf("\r 5.横全亮控开关\n");
printf("\r 6.全亮\n");
printf("\r 7.全灭\n");
printf("\n\n\r");
printf("\r当前运行状态:%c\n",LedStatus);
printf("\r请输入控制序号:");
}
void RCC_Configuration(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO|
RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|
RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD|
RCC_APB2Periph_GPIOE,ENABLE);
}
void Usart_Configuration(void)
{
USART_StructInit(&USART_InitStructure);
USART_InitStructure.USART_BaudRate=9600;
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1,ENABLE);
USART_ClearITPendingBit(USART1,USART_IT_TXE);
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
// USART_ITConfig(USART1,USART_IT_TXE,ENABLE);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOE,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void NVIC_Configuration(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void delayns(u32 nCount)
{
if (SysTick_Config (SystemCoreClock / 1000000))
{ while (1); }
TimeCount=nCount;
while(TimeCount);
SysTick->CTRL=0x00;
SysTick->VAL =0X00;
}
void delayms(u32 nCount)
{
if (SysTick_Config (SystemCoreClock / 1000))
{ while (1); }
TimeCount=nCount;
while(TimeCount);
SysTick->CTRL=0x00;
SysTick->VAL =0X00;
}
回复
有奖活动 | |
---|---|
【EEPW电子工程师创研计划】技术变现通道已开启~ | |
发原创文章 【每月瓜分千元赏金 凭实力攒钱买好礼~】 | |
【EEPW在线】E起听工程师的声音! | |
“我踩过的那些坑”主题活动——第001期 | |
高校联络员开始招募啦!有惊喜!! | |
【工程师专属福利】每天30秒,积分轻松拿!EEPW宠粉打卡计划启动! | |
送您一块开发板,2025年“我要开发板活动”又开始了! | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
【我踩过的那些坑】STM32的硬件通讯调试过程的“坑”被打赏50分 | |
【我踩过的那些坑】晶振使用的问题被打赏100分 | |
【我踩过的那些坑】电感选型错误导致的处理器连接不上被打赏50分 | |
【我踩过的那些坑】工作那些年踩过的记忆深刻的坑被打赏10分 | |
【我踩过的那些坑】DRC使用位置错误导致的问题被打赏100分 | |
我踩过的那些坑之混合OTL功放与落地音箱被打赏50分 | |
汽车电子中巡航控制系统的使用被打赏10分 | |
【我踩过的那些坑】工作那些年踩过的记忆深刻的坑被打赏100分 | |
分享汽车电子中巡航控制系统知识被打赏10分 | |
分享安全气囊系统的检修注意事项被打赏10分 |