这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » BRUCEG ARM-DIY进程贴(串口控制LED)

共21条 2/3 1 2 3 跳转至
菜鸟
2012-03-31 00:43:34     打赏
11楼
论坛有个坏处,希望管理员改进,验证码一旦错误本来打入的长篇大论都没了,这下不得不把精辟论述写成垃圾短文了。(难道就不能用弹窗户,或事实的提醒么?)

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即可。左移算法雷同。


延时明天说了,如今真是又累又没心情了!

菜鸟
2012-03-31 11:04:56     打赏
12楼

非常感谢,好了,能解决了


菜鸟
2012-03-31 12:24:25     打赏
13楼

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就行了
——————————————————————————————————————
纠结这个库是如何实现的呢,继续近一步分析库函数:
(先去打个水喝)


菜鸟
2012-03-31 20:19:08     打赏
14楼
= =  突然打个水完了发现已经是晚上了,继续。

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

菜鸟
2012-04-01 13:30:55     打赏
15楼
好吧应该是_cror_ 才对,我打错了。 烙铁其实尖头的也行的,不过需要点技巧,相对来说没那么好焊,但也是可以焊的。

菜鸟
2012-04-06 12:08:51     打赏
16楼

 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请输入控制序号:");
}
然后终端中看~


界面出来咯。这周忙着,得多等一会再传效果图上来了。


菜鸟
2012-04-08 17:07:26     打赏
17楼
终端软件啊,就PC软件,和串口助手类似,但功能更加强大,没上来发帖两天竟然大家的进度都那么多了,哈哈,我要被追上了

菜鸟
2012-04-10 21:59:12     打赏
18楼

串口的程序前面已经说过了,这里就把前面串口与LED的程序结合起来,做成串口控制LED的模式。








菜鸟
2012-04-10 22:18:20     打赏
19楼

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;

}


菜鸟
2012-04-11 10:30:48     打赏
20楼
没对应好,呵呵,晚上回去再调整调整

共21条 2/3 1 2 3 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]