历史上的今天
返回首页

历史上的今天

今天是:2024年12月14日(星期六)

2019年12月14日 | STM8L051F3基础功能:内部时钟;TIM2定时器;串口及printf

2019-12-14 来源:eefocus

STM8L051调试笔记之基础功能:

系统时钟、串口、定时器都是基础而且必须的功能,这里放在一起统一记录,之所以用TIM2定时器,是因为想实现STM32的滴答定时器功能

这些基础功能没什么好理解的,就直接贴代码了main.c:

main.c:

  void main(void)

  {

    enableInterrupts();

    Sysclk_Init();

    LED_Init();

    Uart1_Init();

  

    

    printf("This is a STM8 code!!!rn");

   

   

   while (1)

   {

     

     if(secondClock_flag)

     {

       secondClock_flag = 0;

       printf("This is a STM8 code!!!rn");

     }

     

     if(calculate_flag)

     {

       calculate_flag = 0;

       printf("a minutern");

     }

   }

}


内部时钟及定时器:

我使用的板子上是没有外部晶振的,所以这里使用的是内部16Mhz的晶振,可以按个人需求对其进行分频。需要说明的是,STM8的程序中,即使没有配置系统时钟,板子依然可以工作,因为默认会有一个2Mhz的内部时钟,这一点在手册中可以查到:

接下来贴代码,由于本人比较懒,只保留的内部时钟的代码,对时钟要求不高的可以参考参考,要求时钟准确的还是用外部晶振吧,代码中附送延时函数,在我的上一篇笔记中有记录

sysclk.c:

#include "sysclk.h"


volatile u8 fac_us=0;


u8 secondClock_flag = 0;

u8 calculate_flag = 0;


void delay_us(u16 nus)

{

  __asm(

"PUSH A          n"

"DELAY_XUS:      n"

"LD A,fac_us     n"

"DELAY_US_1:     n"

"NOP             n"

"DEC A           n"

"JRNE DELAY_US_1 n"

"NOP             n"

"DECW X          n"

"JRNE DELAY_XUS  n"

"POP A           n"

); 

}


void delay_ms(u32 nms)

{

  u8 t;

  if(nms>65)

  {

    t=nms/65;

    while(t--)delay_us(65000);

    nms=nms%65;

  }

  delay_us(nms*1000);

}


void delay_init(u8 clk)

{

  if(clk>16)fac_us=(16-4)/4;

  else if(clk>4)fac_us=(clk-4)/4; 

  else fac_us=1;

}


void TIM2_Init(void)

{

  CLK_PeripheralClockConfig(CLK_Peripheral_TIM2,ENABLE);

  TIM2_TimeBaseInit(TIM2_Prescaler_16,TIM2_CounterMode_Up,1000);  //将系统时钟16分频得到1Mhz,计数1000(或999,未细究)则得到一个每ms进一次的中断,

  TIM2_ARRPreloadConfig(ENABLE);

  TIM2_ITConfig(TIM2_IT_Update,ENABLE);

  

  TIM2_Cmd(ENABLE);

}


void Sysclk_Init(void)

{

  CLK_HSICmd(ENABLE);

  CLK_SYSCLKSourceConfig(CLK_SYSCLKSource_HSI);  //选择HIS内部晶振,

  CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1);  //STM8,HSI为16Mhz,这里1分频即不分频

  

  TIM2_Init();

  delay_init(16);  //参数是系统时钟,这里是16Mhz所以参数为16

}



sysclk.h中内容:

中断stm8l15x_it.c中内容(找到TIM2定时器对应的INTERRUPT_HANDLER):

串口功能:

这里使用的是PA2,PA3两个脚的串口,由于STM8只有8kb的flash,使用printf函数时一不小心就内存不足了,也在网上尝试了很多解决方案,这里我尝试的比较有用的方法是在设置里将printf formatter的值改为Tiny,我这里改为small也是可以的,至于这样会产生什么影响需要再进行分析了,听说改为Tiny是不使用对浮点数的操作,会使对printf相关库函数编译的代码小很多,具体是否如此没有验证,如有错误误导他人请及时批评指正。

贴代码:

uart.c

#include "uart.h"


/**

  * @brief  Configure USART peripheral  

  * @param  None

  * @retval None

  */

void Uart1_Init(void)

{

  /* USART1 configured as follow:

        - BaudRate = 115200 baud  

        - Word Length = 8 Bits

        - One Stop Bit

        - Odd parity

        - Receive and transmit enabled

        - USART Clock disabled

  */

  /* Enable USART clock */

  CLK_PeripheralClockConfig(CLK_Peripheral_USART1, ENABLE);

  

  /* USART1 Tx- Rx remapping to PA2- PA3 */

  SYSCFG_REMAPDeInit();

  SYSCFG_REMAPPinConfig(REMAP_Pin_USART1TxRxPortA, ENABLE);

  

  /* Configure USART Tx pin output*/

  GPIO_Init(GPIOA, GPIO_Pin_2, GPIO_Mode_Out_PP_High_Fast);

  

  /* Configure USART Rx pin input*/

  GPIO_Init(GPIOA, GPIO_Pin_3, GPIO_Mode_In_PU_No_IT);

  

  /* RESET USART1 */

  USART_DeInit(USART1);

  

  /* USART configuration */

  USART_Init(USART1, (u32)115200, USART_WordLength_8b, USART_StopBits_1, USART_Parity_No, USART_Mode_Tx|USART_Mode_Rx);


  /* Enable the USART Receive interrupt: this interrupt is generated when the USART

    receive data register is not empty */

  USART_ClearITPendingBit(USART1, USART_IT_RXNE);

  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

  /* Enable the USART Transmit complete interrupt: this interrupt is generated when the USART

    transmit Shift Register is empty */

  //USART_ITConfig(EVAL_COM1, USART_IT_TC, ENABLE);


  /* Enable USART */

  USART_Cmd(USART1, ENABLE);

}


/* 发送一个字节 */

void UART1_SendByte(u8 data)

{

  USART_SendData8(USART1, data);

  

  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);

}


/* 发送len个字符 */

void UART1_SendStr(u8 *str)

{

  while(*str != '')    

  {    

    UART1_SendByte(*str++);

  }    

}


/* 接收一个字符 */

u8 UART1_ReceiveByte(void)

{

  u8 UART1_RX_BUF; 

      

  while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

  

  UART1_RX_BUF = USART_ReceiveData8(USART1);

  

  return  UART1_RX_BUF;

}


#ifdef _IAR_

int fputc(int ch, FILE *f)

{

  UART1_SendByte(ch);

  return (ch);

}

#else

PUTCHAR_PROTOTYPE

{

  UART1_SendByte(c);

  return (c);

}

#endif


GETCHAR_PROTOTYPE

{

#ifdef _COSMIC_

   char c = 0;

#else

   int c = 0;

#endif

   /* Loop until the Read data register flag is SET */

   while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

   c = USART_ReceiveData8(USART1);

   return (c);

}

uart.h:


#ifndef __UART_H

#define __UART_H


/* 包含系统头文件 */

#include "stm8l15x_conf.h"

#include

#include


/* Private define ------------------------------------------------------------*/

#ifdef _RAISONANCE_

#define PUTCHAR_PROTOTYPE int putchar (char c)

#define GETCHAR_PROTOTYPE int getchar (void)

#elif defined (_COSMIC_)

#define PUTCHAR_PROTOTYPE char putchar (char c)

#define GETCHAR_PROTOTYPE char getchar (void)

#else /* _IAR_ */

#define PUTCHAR_PROTOTYPE int putchar (int c)

#define GETCHAR_PROTOTYPE int getchar (void)

#endif /* _RAISONANCE_ */


void Uart1_Init(void);

void UART1_SendByte(u8 data);

void UART1_SendStr(u8 *str);


#ifdef _IAR_

int fputc(int ch, FILE *f);

#endif


#endif


stm8l15x_it.c中:

推荐阅读

史海拾趣

Goldstar Electron Co Ltd公司的发展小趣事

对于27MHz晶体振荡器电路,网友可能会提出多种问题,以下是一些常见问题及其详细回答:

一、电路设计相关问题

  1. 如何设计一个简单的27MHz晶体振荡器电路?
    • 回答:设计一个简单的27MHz晶体振荡器电路通常包括晶体本身、两个反馈电容、一个或多个电阻以及可能的放大元件(如晶体管或集成电路中的振荡器部分)。例如,可以使用一个并联型晶体振荡器电路,其中晶体与两个电容形成谐振电路,并通过一个放大元件(如CMOS反相器)提供正反馈以维持振荡。具体设计可参考技术资料(如华强电子网)提供的电路图,并根据实际需要进行调整。
  2. 如何选择合适的反馈电容和电阻值?
    • 回答:反馈电容和电阻的选择对振荡器的稳定性和频率精度至关重要。电容值通常根据晶体的规格和所需的振荡频率来确定,而电阻值则用于限制放大器的增益,以防止振荡器过度放大并产生不稳定现象。选择时,建议参考晶体振荡器的数据手册或相关设计指南,并结合实验测试来找到最佳值。

二、电路性能相关问题

  1. 如何减少27MHz晶体振荡器的谐波失真?
    • 回答:谐波失真通常是由于电路中的非线性元件或设计不当引起的。为了减少谐波失真,可以采取以下措施:
      • 选择低谐波失真的晶体振荡器。
      • 在电路中添加低通滤波器以滤除高频谐波。
      • 优化电路设计,减少非线性元件的使用,并确保电路元件的匹配性。
  2. 如何提高27MHz晶体振荡器的频率稳定性?
    • 回答:频率稳定性受多种因素影响,包括晶体的物理特性、环境温度、电源电压波动等。提高频率稳定性的方法包括:
      • 选择高质量的晶体振荡器,确保其具有较低的频率漂移和温度系数。
      • 在电路中添加温度补偿电路,以抵消温度变化对频率的影响。
      • 使用稳定的电源电压,并在必要时添加电压稳压器。
      • 优化电路布局和接地设计,减少电磁干扰和噪声。

三、电路调试与测试相关问题

  1. 如何调试27MHz晶体振荡器电路以确保其正常工作?
    • 回答:调试晶体振荡器电路时,可以按照以下步骤进行:
      • 检查电路连接是否正确,确保所有元件都已正确安装。
      • 使用示波器观察振荡波形,确认其频率和幅度是否符合要求。
      • 调整反馈电容和电阻值,以优化振荡器的性能和稳定性。
      • 检查电源电压和电流是否稳定,并调整至推荐值。
      • 如果发现谐波失真或其他问题,根据具体情况采取相应的解决措施。
  2. 如何测试27MHz晶体振荡器的输出频率和相位噪声?
    • 回答:测试晶体振荡器的输出频率和相位噪声通常需要使用专业的测试设备,如频率计和相位噪声分析仪。测试时,将振荡器的输出连接到测试设备的输入端,并设置适当的测试参数。通过测试设备可以准确测量振荡器的输出频率和相位噪声水平,从而评估其性能是否符合要求。

四、其他常见问题

  1. 27MHz晶体振荡器适用于哪些应用场景?
    • 回答:27MHz晶体振荡器由于其较高的频率和较好的稳定性,广泛应用于无线通信、雷达系统、电子测量仪器等领域。在这些应用场景中,晶体振荡器作为时钟源或频率基准,为系统提供稳定的频率信号。
  2. 如何延长27MHz晶体振荡器的使用寿命?
    • 回答:延长晶体振荡器的使用寿命需要注意以下几点:
      • 避免在极端温度或湿度条件下使用。
      • 保持电源电压稳定,避免频繁波动。
      • 定期检查电路连接和元件状态,及时更换损坏的元件。
      • 避免机械冲击和振动对晶体振荡器的影响。
      • 选择质量可靠、性能稳定的晶体振荡器产品。
Compact公司的发展小趣事

在快速发展的过程中,Compact公司始终注重品牌建设和文化传承。公司通过不断提升产品质量和服务水平,树立了良好的品牌形象。同时,公司还注重培养员工的归属感和忠诚度,形成了独特的企业文化。这种文化传承不仅为公司的发展提供了强大的精神动力,还使公司在激烈的市场竞争中保持了独特的竞争力。

德丰(DEFOND)公司的发展小趣事

德丰金属材料有限公司(简称“德丰金属”)是一家专业从事铝合金建筑型材加工的企业。随着市场竞争的加剧和环保要求的提高,公司意识到必须加快转型升级的步伐。为此,德丰金属加大了研发投入和技术改造力度,成功开发出了一系列符合绿色环保标准的新型铝合金型材产品。同时,公司还积极拓展国际市场,与多家国外知名企业建立了长期稳定的合作关系。通过不断的努力和创新,德丰金属成功实现了从传统制造业向绿色环保型制造业的转型升级。

DREMEL公司的发展小趣事

Dremio公司深知人才对于企业发展的重要性。因此,他们积极投资教育领域,支持数据科学和数据分析人才的培养。他们与多所高校合作,设立奖学金和实习项目,鼓励学生参与数据治理和云数据湖领域的研究和实践。同时,Dremio还建立了一个活跃的社区平台,为数据湖实践者提供交流和学习的机会。这些举措不仅为Dremio公司吸引了大量优秀人才,也推动了整个电子行业的发展。

Allied Electronic & Semiconductor Technology Inc公司的发展小趣事

AE&ST公司自创立之初,就深知技术创新是电子行业的核心竞争力。公司投入大量资源进行研发,不断探索新的半导体材料和生产工艺。在一次偶然的实验中,AE&ST的研发团队发现了一种新型半导体材料,这种材料在能效和稳定性方面表现出色。公司迅速将这一发现转化为产品,并推向市场。新产品一经推出,便因其卓越的性能获得了市场的广泛认可,AE&ST公司因此获得了巨大的商业成功。

ES Systems公司的发展小趣事

ES Systems在创立初期主要面向高端市场提供定制化服务。然而,随着市场竞争的加剧和客户需求的变化,公司意识到必须调整市场策略。于是,ES Systems开始加大在中低端市场的投入,推出了一系列性价比高的产品。这一策略的调整使得公司的市场份额迅速扩大,同时也提高了品牌知名度。

问答坊 | AI 解惑

一种能同时使用两种格式(TV/DVD)的红外遥控器(转)

通过切换开关,就能发送不同格式的TV遥控码或DVD遥控码,目前按键只有6个,大家可以自己增加. …

查看全部问答>

怎样用C#开发出在PDA上使用的画笔?

如题, 也就是跟踪触笔轨迹,把移动的轨迹画出来,可以清除,保存图象.…

查看全部问答>

关于UI库

    本人菜鸟,想了解一下UI库是什么东西。一个高手让我和他一起做,用EVC,嵌入式方面的。我需要点什么参考的东西?或者大概给我解释一下一个UI库应该具备的框架什么的。谢谢大家…

查看全部问答>

我想转向Linux驱动开发,请教各位一些问题

感谢抽空看我帖子的GG和MM,我工作半年了.我的公司是专门给保险公司做软件的,主要用unix  c  .我在大学的时候是学软件的,我的计算机理论,数据结构,操作系统数据库,比较扎实,还有熟悉JAVA和C/C++,但是我没接触过硬件的知识,比如 ...…

查看全部问答>

==h2023197 (微笑刺客) 和各位前辈请指教==st16c550的驱动的问题

请教一下st16c550的驱动的问题,这个片子应该和st16c554兼容。 -------- 我用的是s3c2410开发板+wince5.0。eINT13连接到16550的INT脚; fpga (xc9536)的14脚  ST16c550_CS 经过244转换后,作为st16c550的片选;在cpld的程 ...…

查看全部问答>

st7系列的乘法指令

st7mc有8位无符号乘法指令,在汇编下使用情况就不说了。但是在用c语言编程时如果c(16bit)=a(8bit)*b(8bit),cosmic编译后的汇编代码是怎么样的?cosmic会直接用那个乘法指令么,还是像我们以前的那种移位加法运算耗去几十条指令?另外那 ...…

查看全部问答>

存储数据到指定的Flash区域问题?

程序中有一部分数据需要存储在指定的Flash地址部分,此部分数据可以更新。存储方式如下: u16 Numbers[2] __at(Flash_Addr)={3246,1048};    其中Flash_Addr = 0x08038000; 以这样的方式定义后用Flash Loader烧写时速度很慢。主 ...…

查看全部问答>

找工作。。。 做了一年的资料,现在想做专业的也难,什么电路的分析全部忘记完!这两周都再努力看书,但是不是在这里被卡就是在那里被卡,看得头都大了!网上的资料下载了一个又一个,但是打开一看,发现很多不是自己需要的东西!连个二极管的限幅 ...…

查看全部问答>

avr串口通信

用avr串口通信时,pl2303的晶振频率会影响到波特率的设置吗…

查看全部问答>