怀揣少年梦

个性签名:

阅读改变人生

  • 2025-03-25
  • 回复了主题帖: 【NUCLEO-U083RE开发板测评】06 STM32U0驱动液晶屏

    Jacktang 发表于 2025-3-23 08:53 可以, 还介绍了 液晶屏显示的来龙去脉 多谢大佬鼓励

  • 2025-03-21
  • 发表了主题帖: 【NUCLEO-U083RE开发板测评】06 STM32U0驱动液晶屏

    本帖最后由 怀揣少年梦 于 2025-3-21 16:41 编辑 LCD液晶屏是众多嵌入式开发工程师常用屏幕之一,这次测评也使用LCD液晶进行测试 一、LCD简介 LCD(Liquid Crystal Display,液晶显示器)是一种利用液晶材料的光电特性实现图像显示的平板显示技术。其核心原理是通过电场控制液晶分子的排列,从而改变光的偏振状态,配合背光源和滤光片生成图像 1、技术特性: ​结构组成:主要包括液晶层、偏振膜、玻璃基板、驱动电路及背光模组。偏振膜垂直排列,通过电场控制液晶分子扭转角度,调节透光量 ​核心优势:低功耗(1-10微瓦/平方厘米)、轻薄化(厚度可低至5厘米)、无辐射、高分辨率 ​技术分类:TN(扭曲向列型)、STN(超扭曲向列型)、TFT(薄膜晶体管型)等,其中TFT-LCD因响应速度和色彩表现优异,成为主流。 2、发展历程: 19世纪末奥地利学者发现液晶特性,20世纪70年代首款TN-LCD应用于电子表、计算器; 1998年后逐步取代CRT显示器,成为计算机、电视等领域的标准配置。 ​二、LCD液晶屏的主要用途 LCD凭借其技术优势,覆盖从消费电子到工业设备的广泛领域: 1、图像显示 ​ 基础功能:通过像素阵列呈现静态或动态画面,支持彩色滤光片实现全彩显示 ​ 信号兼容性:支持模拟与数字信号输入,需通过APC模块转换信号类型 2、信息交互: 作为人机界面(HMI),用于触控操作、参数设置及数据反馈 三、实际应用 本次使用U083开发板驱动2.5寸 TFT-LCD 显示屏(ILI9341驱动芯片); 1、工程配置 1)配置时钟   2)配置相关SPI接口   2、移植相关代码 相关LCD代码 /* [url=home.php?mod=space&uid=1020061]@attention[/url] * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, QD electronic SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. **************************************************************************************************/ #include "lcd.h" #include "spi.h" #include <stdio.h> //管理LCD重要参数 //默认为竖屏 _lcd_dev lcddev; //画笔颜色,背景颜色 uint16_t POINT_COLOR = 0x0000,BACK_COLOR = 0xFFFF; uint16_t DeviceCode; uint8_t LCD_SPI_WriteByte(uint8_t TxData) { uint8_t RxData = 0X00; if(HAL_SPI_TransmitReceive(LCD_SPI_Handle, &TxData, &RxData, 1, 100) != HAL_OK) { RxData = 0XFF; } return RxData; } /***************************************************************************** * [url=home.php?mod=space&uid=32621]@name[/url] :void LCD_WR_REG(uint8_t data) * [url=home.php?mod=space&uid=311857]@date[/url] :2018-08-09 * [url=home.php?mod=space&uid=665173]@FUNCTION[/url] :Write an 8-bit command to the LCD screen * @parameters :data:Command value to be written * @retvalue :None ******************************************************************************/ void LCD_WR_REG(uint8_t data) { LCD_CS_CLR; LCD_RS_CLR; LCD_SPI_WriteByte(data); LCD_CS_SET; } /***************************************************************************** * @name :void LCD_WR_DATA(uint8_t data) * @date :2018-08-09 * @function :Write an 8-bit data to the LCD screen * @parameters :data:data value to be written * @retvalue :None ******************************************************************************/ void LCD_WR_DATA(uint8_t data) { LCD_CS_CLR; LCD_RS_SET; LCD_SPI_WriteByte(data); LCD_CS_SET; } /***************************************************************************** * @name :void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue) * @date :2018-08-09 * @function :Write data into registers * @parameters :LCD_Reg:Register address LCD_RegValue:Data to be written * @retvalue :None ******************************************************************************/ void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue) { LCD_WR_REG(LCD_Reg); LCD_WR_DATA(LCD_RegValue); } /***************************************************************************** * @name :void LCD_WriteRAM_Prepare(void) * @date :2018-08-09 * @function :Write GRAM * @parameters :None * @retvalue :None ******************************************************************************/ void LCD_WriteRAM_Prepare(void) { LCD_WR_REG(lcddev.wramcmd); } /***************************************************************************** * @name :void Lcd_WriteData_16Bit(uint16_t Data) * @date :2018-08-09 * @function :Write an 16-bit command to the LCD screen * @parameters :Data:Data to be written * @retvalue :None ******************************************************************************/ void Lcd_WriteData_16Bit(uint16_t Data) { LCD_CS_CLR; LCD_RS_SET; LCD_SPI_WriteByte(Data>>8); LCD_SPI_WriteByte(Data); LCD_CS_SET; } /***************************************************************************** * @name :void LCD_DrawPoint(uint16_t x,uint16_t y) * @date :2018-08-09 * @function :Write a pixel data at a specified location * @parameters :x:the x coordinate of the pixel y:the y coordinate of the pixel * @retvalue :None ******************************************************************************/ void LCD_DrawPoint(uint16_t x,uint16_t y) { LCD_SetCursor(x,y);//设置光标位置 Lcd_WriteData_16Bit(POINT_COLOR); } /***************************************************************************** * @name :void LCD_Clear(uint16_t Color) * @date :2018-08-09 * @function :Full screen filled LCD screen * @parameters :color:Filled color * @retvalue :None ******************************************************************************/ void LCD_Clear(uint16_t Color) { unsigned int i,m; LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1); LCD_CS_CLR; LCD_RS_SET; for(i=0;i<lcddev.height;i++) { for(m=0;m<lcddev.width;m++) { Lcd_WriteData_16Bit(Color); } } LCD_CS_SET; } /***************************************************************************** * @name :void LCD_RESET(void) * @date :2018-08-09 * @function :Reset LCD screen * @parameters :None * @retvalue :None ******************************************************************************/ void LCD_RESET(void) { LCD_RST_CLR; HAL_Delay(100); LCD_RST_SET; HAL_Delay(50); } /***************************************************************************** * @name :void LCD_RESET(void) * @date :2018-08-09 * @function :Initialization LCD screen * @parameters :None * @retvalue :None ******************************************************************************/ void LCD_Init(void) { LCD_RESET(); //LCD 复位 //*************3.2inch ILI9341初始化**********// LCD_WR_REG(0xCF); LCD_WR_DATA(0x00); LCD_WR_DATA(0xD9); //C1 LCD_WR_DATA(0X30); LCD_WR_REG(0xED); LCD_WR_DATA(0x64); LCD_WR_DATA(0x03); LCD_WR_DATA(0X12); LCD_WR_DATA(0X81); LCD_WR_REG(0xE8); LCD_WR_DATA(0x85); LCD_WR_DATA(0x10); LCD_WR_DATA(0x7A); LCD_WR_REG(0xCB); LCD_WR_DATA(0x39); LCD_WR_DATA(0x2C); LCD_WR_DATA(0x00); LCD_WR_DATA(0x34); LCD_WR_DATA(0x02); LCD_WR_REG(0xF7); LCD_WR_DATA(0x20); LCD_WR_REG(0xEA); LCD_WR_DATA(0x00); LCD_WR_DATA(0x00); LCD_WR_REG(0xC0); //Power control LCD_WR_DATA(0x1B); //VRH[5:0] LCD_WR_REG(0xC1); //P0 LCD_WR_DATA(0x12); //SAP[2:0];BT[3:0] //0x01 LCD_WR_REG(0xC5); //VCM control LCD_WR_DATA(0x26); //3F LCD_WR_DATA(0x26); //3C LCD_WR_REG(0xC7); //VCM control2 LCD_WR_DATA(0XB0); LCD_WR_REG(0x36); // Memory Access Control LCD_WR_DATA(0x08); LCD_WR_REG(0x3A); LCD_WR_DATA(0x55); LCD_WR_REG(0xB1); LCD_WR_DATA(0x00); LCD_WR_DATA(0x1A); LCD_WR_REG(0xB6); // Display Function Control LCD_WR_DATA(0x0A); LCD_WR_DATA(0xA2); LCD_WR_REG(0xF2); // 3Gamma Function Disable LCD_WR_DATA(0x00); LCD_WR_REG(0x26); //Gamma curve selected LCD_WR_DATA(0x01); LCD_WR_REG(0xE0); //Set Gamma LCD_WR_DATA(0x1F); LCD_WR_DATA(0x24); LCD_WR_DATA(0x24); LCD_WR_DATA(0x0D); LCD_WR_DATA(0x12); LCD_WR_DATA(0x09); LCD_WR_DATA(0x52); LCD_WR_DATA(0xB7); LCD_WR_DATA(0x3F); LCD_WR_DATA(0x0C); LCD_WR_DATA(0x15); LCD_WR_DATA(0x06); LCD_WR_DATA(0x0E); LCD_WR_DATA(0x08); LCD_WR_DATA(0x00); LCD_WR_REG(0XE1); //Set Gamma LCD_WR_DATA(0x00); LCD_WR_DATA(0x1B); LCD_WR_DATA(0x1B); LCD_WR_DATA(0x02); LCD_WR_DATA(0x0E); LCD_WR_DATA(0x06); LCD_WR_DATA(0x2E); LCD_WR_DATA(0x48); LCD_WR_DATA(0x3F); LCD_WR_DATA(0x03); LCD_WR_DATA(0x0A); LCD_WR_DATA(0x09); LCD_WR_DATA(0x31); LCD_WR_DATA(0x37); LCD_WR_DATA(0x1F); LCD_WR_REG(0x2B); LCD_WR_DATA(0x00); LCD_WR_DATA(0x00); LCD_WR_DATA(0x01); LCD_WR_DATA(0x3f); LCD_WR_REG(0x2A); LCD_WR_DATA(0x00); LCD_WR_DATA(0x00); LCD_WR_DATA(0x00); LCD_WR_DATA(0xef); LCD_WR_REG(0x11); //Exit Sleep HAL_Delay(120); LCD_WR_REG(0x29); //display on LCD_direction(USE_HORIZONTAL);//设置LCD显示方向 LCD_BL_ON;//点亮背光 LCD_Clear(GREEN);//清全屏白色 } /***************************************************************************** * @name :void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd) * @date :2018-08-09 * @function :Setting LCD display window * @parameters :xStar:the bebinning x coordinate of the LCD display window yStar:the bebinning y coordinate of the LCD display window xEnd:the endning x coordinate of the LCD display window yEnd:the endning y coordinate of the LCD display window * @retvalue :None ******************************************************************************/ void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd) { LCD_WR_REG(lcddev.setxcmd); LCD_WR_DATA(xStar>>8); LCD_WR_DATA(0x00FF&xStar); LCD_WR_DATA(xEnd>>8); LCD_WR_DATA(0x00FF&xEnd); LCD_WR_REG(lcddev.setycmd); LCD_WR_DATA(yStar>>8); LCD_WR_DATA(0x00FF&yStar); LCD_WR_DATA(yEnd>>8); LCD_WR_DATA(0x00FF&yEnd); LCD_WriteRAM_Prepare(); //开始写入GRAM } /***************************************************************************** * @name :void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos) * @date :2018-08-09 * @function :Set coordinate value * @parameters :Xpos:the x coordinate of the pixel Ypos:the y coordinate of the pixel * @retvalue :None ******************************************************************************/ void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos) { LCD_SetWindows(Xpos,Ypos,Xpos,Ypos); } /***************************************************************************** * @name :void LCD_direction(uint8_t direction) * @date :2018-08-09 * @function :Setting the display direction of LCD screen * @parameters :direction:0-0 degree 1-90 degree 2-180 degree 3-270 degree * @retvalue :None ******************************************************************************/ void LCD_direction(uint8_t direction) { lcddev.setxcmd=0x2A; lcddev.setycmd=0x2B; lcddev.wramcmd=0x2C; switch(direction){ case 0: lcddev.width=LCD_W; lcddev.height=LCD_H; LCD_WriteReg(0x36,(1<<3)|(0<<6)|(0<<7));//BGR==1,MY==0,MX==0,MV==0 break; case 1: lcddev.width=LCD_H; lcddev.height=LCD_W; LCD_WriteReg(0x36,(1<<3)|(0<<7)|(1<<6)|(1<<5));//BGR==1,MY==1,MX==0,MV==1 break; case 2: lcddev.width=LCD_W; lcddev.height=LCD_H; LCD_WriteReg(0x36,(1<<3)|(1<<6)|(1<<7));//BGR==1,MY==0,MX==0,MV==0 break; case 3: lcddev.width=LCD_H; lcddev.height=LCD_W; LCD_WriteReg(0x36,(1<<3)|(1<<7)|(1<<5));//BGR==1,MY==1,MX==0,MV==1 break; default:break; } }   相关GUI代码 /* @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, QD electronic SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. **************************************************************************************************/ #include "lcd.h" #include "string.h" #include "gui.h" #include "font.h" /******************************************************************* * @name :void GUI_DrawPoint(uint16_t x,uint16_t y,uint16_t color) * @date :2018-08-09 * @function :draw a point in LCD screen * @parameters :x:the x coordinate of the point y:the y coordinate of the point color:the color value of the point * @retvalue :None ********************************************************************/ void GUI_DrawPoint(uint16_t x,uint16_t y,uint16_t color) { LCD_SetCursor(x,y);//设置光标位置 Lcd_WriteData_16Bit(color); } /******************************************************************* * @name :void LCD_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t color) * @date :2018-08-09 * @function :fill the specified area * @parameters :sx:the bebinning x coordinate of the specified area sy:the bebinning y coordinate of the specified area ex:the ending x coordinate of the specified area ey:the ending y coordinate of the specified area color:the filled color value * @retvalue :None ********************************************************************/ void LCD_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t color) { uint16_t i,j; uint16_t width=ex-sx+1; //得到填充的宽度 uint16_t height=ey-sy+1; //高度 LCD_SetWindows(sx,sy,ex,ey);//设置显示窗口 for(i=0;i<height;i++) { for(j=0;j<width;j++) Lcd_WriteData_16Bit(color); //写入数据 } LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口设置为全屏 } /******************************************************************* * @name :void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) * @date :2018-08-09 * @function :Draw a line between two points * @parameters :x1:the bebinning x coordinate of the line y1:the bebinning y coordinate of the line x2:the ending x coordinate of the line y2:the ending y coordinate of the line * @retvalue :None ********************************************************************/ void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { uint16_t t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; delta_x=x2-x1; //计算坐标增量 delta_y=y2-y1; uRow=x1; uCol=y1; if(delta_x>0)incx=1; //设置单步方向 else if(delta_x==0)incx=0;//垂直线 else {incx=-1;delta_x=-delta_x;} if(delta_y>0)incy=1; else if(delta_y==0)incy=0;//水平线 else{incy=-1;delta_y=-delta_y;} if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 else distance=delta_y; for(t=0;t<=distance+1;t++ )//画线输出 { LCD_DrawPoint(uRow,uCol);//画点 xerr+=delta_x ; yerr+=delta_y ; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } } /***************************************************************************** * @name :void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) * @date :2018-08-09 * @function :Draw a rectangle * @parameters :x1:the bebinning x coordinate of the rectangle y1:the bebinning y coordinate of the rectangle x2:the ending x coordinate of the rectangle y2:the ending y coordinate of the rectangle * @retvalue :None ******************************************************************************/ void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { LCD_DrawLine(x1,y1,x2,y1); LCD_DrawLine(x1,y1,x1,y2); LCD_DrawLine(x1,y2,x2,y2); LCD_DrawLine(x2,y1,x2,y2); } /***************************************************************************** * @name :void LCD_DrawFillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) * @date :2018-08-09 * @function :Filled a rectangle * @parameters :x1:the bebinning x coordinate of the filled rectangle y1:the bebinning y coordinate of the filled rectangle x2:the ending x coordinate of the filled rectangle y2:the ending y coordinate of the filled rectangle * @retvalue :None ******************************************************************************/ void LCD_DrawFillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { LCD_Fill(x1,y1,x2,y2,POINT_COLOR); } /***************************************************************************** * @name :void _draw_circle_8(int xc, int yc, int x, int y, uint16_t c) * @date :2018-08-09 * @function :8 symmetry circle drawing algorithm (internal call) * @parameters :xc:the x coordinate of the Circular center yc:the y coordinate of the Circular center x:the x coordinate relative to the Circular center y:the y coordinate relative to the Circular center c:the color value of the circle * @retvalue :None ******************************************************************************/ void _draw_circle_8(int xc, int yc, int x, int y, uint16_t c) { GUI_DrawPoint(xc + x, yc + y, c); GUI_DrawPoint(xc - x, yc + y, c); GUI_DrawPoint(xc + x, yc - y, c); GUI_DrawPoint(xc - x, yc - y, c); GUI_DrawPoint(xc + y, yc + x, c); GUI_DrawPoint(xc - y, yc + x, c); GUI_DrawPoint(xc + y, yc - x, c); GUI_DrawPoint(xc - y, yc - x, c); } /***************************************************************************** * @name :void gui_circle(int xc, int yc,uint16_t c,int r, int fill) * @date :2018-08-09 * @function :Draw a circle of specified size at a specified location * @parameters :xc:the x coordinate of the Circular center yc:the y coordinate of the Circular center r:Circular radius fill:1-filling,0-no filling * @retvalue :None ******************************************************************************/ void gui_circle(int xc, int yc,uint16_t c,int r, int fill) { int x = 0, y = r, yi, d; d = 3 - 2 * r; if (fill) { // 如果填充(画实心圆) while (x <= y) { for (yi = x; yi <= y; yi++) _draw_circle_8(xc, yc, x, yi, c); if (d < 0) { d = d + 4 * x + 6; } else { d = d + 4 * (x - y) + 10; y--; } x++; } } else { // 如果不填充(画空心圆) while (x <= y) { _draw_circle_8(xc, yc, x, y, c); if (d < 0) { d = d + 4 * x + 6; } else { d = d + 4 * (x - y) + 10; y--; } x++; } } } /***************************************************************************** * @name :void Draw_Triangel(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) * @date :2018-08-09 * @function :Draw a triangle at a specified position * @parameters :x0:the bebinning x coordinate of the triangular edge y0:the bebinning y coordinate of the triangular edge x1:the vertex x coordinate of the triangular y1:the vertex y coordinate of the triangular x2:the ending x coordinate of the triangular edge y2:the ending y coordinate of the triangular edge * @retvalue :None ******************************************************************************/ void Draw_Triangel(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { LCD_DrawLine(x0,y0,x1,y1); LCD_DrawLine(x1,y1,x2,y2); LCD_DrawLine(x2,y2,x0,y0); } static void _swap(uint16_t *a, uint16_t *b) { uint16_t tmp; tmp = *a; *a = *b; *b = tmp; } /***************************************************************************** * @name :void Fill_Triangel(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) * @date :2018-08-09 * @function :filling a triangle at a specified position * @parameters :x0:the bebinning x coordinate of the triangular edge y0:the bebinning y coordinate of the triangular edge x1:the vertex x coordinate of the triangular y1:the vertex y coordinate of the triangular x2:the ending x coordinate of the triangular edge y2:the ending y coordinate of the triangular edge * @retvalue :None ******************************************************************************/ void Fill_Triangel(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { uint16_t a, b, y, last; int dx01, dy01, dx02, dy02, dx12, dy12; long sa = 0; long sb = 0; if (y0 > y1) { _swap(&y0,&y1); _swap(&x0,&x1); } if (y1 > y2) { _swap(&y2,&y1); _swap(&x2,&x1); } if (y0 > y1) { _swap(&y0,&y1); _swap(&x0,&x1); } if(y0 == y2) { a = b = x0; if(x1 < a) { a = x1; } else if(x1 > b) { b = x1; } if(x2 < a) { a = x2; } else if(x2 > b) { b = x2; } LCD_Fill(a,y0,b,y0,POINT_COLOR); return; } dx01 = x1 - x0; dy01 = y1 - y0; dx02 = x2 - x0; dy02 = y2 - y0; dx12 = x2 - x1; dy12 = y2 - y1; if(y1 == y2) { last = y1; } else { last = y1-1; } for(y=y0; y<=last; y++) { a = x0 + sa / dy01; b = x0 + sb / dy02; sa += dx01; sb += dx02; if(a > b) { _swap(&a,&b); } LCD_Fill(a,y,b,y,POINT_COLOR); } sa = dx12 * (y - y1); sb = dx02 * (y - y0); for(; y<=y2; y++) { a = x1 + sa / dy12; b = x0 + sb / dy02; sa += dx12; sb += dx02; if(a > b) { _swap(&a,&b); } LCD_Fill(a,y,b,y,POINT_COLOR); } } /***************************************************************************** * @name :void LCD_ShowChar(uint16_t x,uint16_t y,uint16_t fc, uint16_t bc, uint8_t num,uint8_t size,uint8_t mode) * @date :2018-08-09 * @function :Display a single English character * @parameters :x:the bebinning x coordinate of the Character display position y:the bebinning y coordinate of the Character display position fc:the color value of display character bc:the background color of display character num:the ascii code of display character(0~94) size:the size of display character mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void LCD_ShowChar(uint16_t x,uint16_t y,uint16_t fc, uint16_t bc, uint8_t num,uint8_t size,uint8_t mode) { uint8_t temp; uint8_t pos,t; uint16_t colortemp=POINT_COLOR; num=num-' ';//得到偏移后的值 LCD_SetWindows(x,y,x+size/2-1,y+size-1);//设置单个文字显示窗口 if(!mode) //非叠加方式 { for(pos=0;pos<size;pos++) { if(size==12)temp=asc2_1206[num][pos];//调用1206字体 else temp=asc2_1608[num][pos]; //调用1608字体 for(t=0;t<size/2;t++) { if(temp&0x01)Lcd_WriteData_16Bit(fc); else Lcd_WriteData_16Bit(bc); temp>>=1; } } }else//叠加方式 { for(pos=0;pos<size;pos++) { if(size==12)temp=asc2_1206[num][pos];//调用1206字体 else temp=asc2_1608[num][pos]; //调用1608字体 for(t=0;t<size/2;t++) { POINT_COLOR=fc; if(temp&0x01)LCD_DrawPoint(x+t,y+pos);//画一个点 temp>>=1; } } } POINT_COLOR=colortemp; LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口为全屏 } /***************************************************************************** * @name :void LCD_ShowString(uint16_t x,uint16_t y,uint8_t size,uint8_t *p,uint8_t mode) * @date :2018-08-09 * @function :Display English string * @parameters :x:the bebinning x coordinate of the English string y:the bebinning y coordinate of the English string p:the start address of the English string size:the size of display character mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void LCD_ShowString(uint16_t x,uint16_t y,uint8_t size,uint8_t *p,uint8_t mode) { while((*p<='~')&&(*p>=' '))//判断是不是非法字符! { if(x>(lcddev.width-1)||y>(lcddev.height-1)) return; LCD_ShowChar(x,y,POINT_COLOR,BACK_COLOR,*p,size,mode); x+=size/2; p++; } } /***************************************************************************** * @name :uint32_t mypow(uint8_t m,uint8_t n) * @date :2018-08-09 * @function :get the nth power of m (internal call) * @parameters :m:the multiplier n:the power * @retvalue :the nth power of m ******************************************************************************/ uint32_t mypow(uint8_t m,uint8_t n) { uint32_t result=1; while(n--)result*=m; return result; } /***************************************************************************** * @name :void LCD_ShowNum(uint16_t x,uint16_t y,uint32_t num,uint8_t len,uint8_t size) * @date :2018-08-09 * @function :Display number * @parameters :x:the bebinning x coordinate of the number y:the bebinning y coordinate of the number num:the number(0~4294967295) len:the length of the display number size:the size of display number * @retvalue :None ******************************************************************************/ void LCD_ShowNum(uint16_t x,uint16_t y,uint32_t num,uint8_t len,uint8_t size) { uint8_t t,temp; uint8_t enshow=0; for(t=0;t<len;t++) { temp=(num/mypow(10,len-t-1))%10; if(enshow==0&&t<(len-1)) { if(temp==0) { LCD_ShowChar(x+(size/2)*t,y,POINT_COLOR,BACK_COLOR,' ',size,0); continue; }else enshow=1; } LCD_ShowChar(x+(size/2)*t,y,POINT_COLOR,BACK_COLOR,temp+'0',size,0); } } /***************************************************************************** * @name :void GUI_DrawFont16(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s,uint8_t mode) * @date :2018-08-09 * @function :Display a single 16x16 Chinese character * @parameters :x:the bebinning x coordinate of the Chinese character y:the bebinning y coordinate of the Chinese character fc:the color value of Chinese character bc:the background color of Chinese character s:the start address of the Chinese character mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void GUI_DrawFont16(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s,uint8_t mode) { uint8_t i,j; uint16_t k; uint16_t HZnum; uint16_t x0=x; HZnum=sizeof(tfont16)/sizeof(typFNT_GB16); //自动统计汉字数目 for (k=0;k<HZnum;k++) { if ((tfont16[k].Index[0]==*(s))&&(tfont16[k].Index[1]==*(s+1))) { LCD_SetWindows(x,y,x+16-1,y+16-1); for(i=0;i<16*2;i++) { for(j=0;j<8;j++) { if(!mode) //非叠加方式 { if(tfont16[k].Msk[i]&(0x80>>j)) Lcd_WriteData_16Bit(fc); else Lcd_WriteData_16Bit(bc); } else { POINT_COLOR=fc; if(tfont16[k].Msk[i]&(0x80>>j)) LCD_DrawPoint(x,y);//画一个点 x++; if((x-x0)==16) { x=x0; y++; break; } } } } } continue; //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响 } LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口为全屏 } /***************************************************************************** * @name :void GUI_DrawFont24(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s,uint8_t mode) * @date :2018-08-09 * @function :Display a single 24x24 Chinese character * @parameters :x:the bebinning x coordinate of the Chinese character y:the bebinning y coordinate of the Chinese character fc:the color value of Chinese character bc:the background color of Chinese character s:the start address of the Chinese character mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void GUI_DrawFont24(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s,uint8_t mode) { uint8_t i,j; uint16_t k; uint16_t HZnum; uint16_t x0=x; HZnum=sizeof(tfont24)/sizeof(typFNT_GB24); //自动统计汉字数目 for (k=0;k<HZnum;k++) { if ((tfont24[k].Index[0]==*(s))&&(tfont24[k].Index[1]==*(s+1))) { LCD_SetWindows(x,y,x+24-1,y+24-1); for(i=0;i<24*3;i++) { for(j=0;j<8;j++) { if(!mode) //非叠加方式 { if(tfont24[k].Msk[i]&(0x80>>j)) Lcd_WriteData_16Bit(fc); else Lcd_WriteData_16Bit(bc); } else { POINT_COLOR=fc; if(tfont24[k].Msk[i]&(0x80>>j)) LCD_DrawPoint(x,y);//画一个点 x++; if((x-x0)==24) { x=x0; y++; break; } } } } } continue; //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响 } LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口为全屏 } /***************************************************************************** * @name :void GUI_DrawFont32(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s,uint8_t mode) * @date :2018-08-09 * @function :Display a single 32x32 Chinese character * @parameters :x:the bebinning x coordinate of the Chinese character y:the bebinning y coordinate of the Chinese character fc:the color value of Chinese character bc:the background color of Chinese character s:the start address of the Chinese character mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void GUI_DrawFont32(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s,uint8_t mode) { uint8_t i,j; uint16_t k; uint16_t HZnum; uint16_t x0=x; HZnum=sizeof(tfont32)/sizeof(typFNT_GB32); //自动统计汉字数目 for (k=0;k<HZnum;k++) { if ((tfont32[k].Index[0]==*(s))&&(tfont32[k].Index[1]==*(s+1))) { LCD_SetWindows(x,y,x+32-1,y+32-1); for(i=0;i<32*4;i++) { for(j=0;j<8;j++) { if(!mode) //非叠加方式 { if(tfont32[k].Msk[i]&(0x80>>j)) Lcd_WriteData_16Bit(fc); else Lcd_WriteData_16Bit(bc); } else { POINT_COLOR=fc; if(tfont32[k].Msk[i]&(0x80>>j)) LCD_DrawPoint(x,y);//画一个点 x++; if((x-x0)==32) { x=x0; y++; break; } } } } } continue; //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响 } LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口为全屏 } /***************************************************************************** * @name :void Show_Str(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *str,uint8_t size,uint8_t mode) * @date :2018-08-09 * @function :Display Chinese and English strings * @parameters :x:the bebinning x coordinate of the Chinese and English strings y:the bebinning y coordinate of the Chinese and English strings fc:the color value of Chinese and English strings bc:the background color of Chinese and English strings str:the start address of the Chinese and English strings size:the size of Chinese and English strings mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void Show_Str(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *str,uint8_t size,uint8_t mode) { uint16_t x0=x; uint8_t bHz=0; //字符或者中文 while(*str!=0)//数据未结束 { if(!bHz) { if(x>(lcddev.width-size/2)||y>(lcddev.height-size)) return; if(*str>0x80)bHz=1;//中文 else //字符 { if(*str==0x0D)//换行符号 { y+=size; x=x0; str++; } else { if(size>16)//字库中没有集成12X24 16X32的英文字体,用8X16代替 { LCD_ShowChar(x,y,fc,bc,*str,16,mode); x+=8; //字符,为全字的一半 } else { LCD_ShowChar(x,y,fc,bc,*str,size,mode); x+=size/2; //字符,为全字的一半 } } str++; } }else//中文 { if(x>(lcddev.width-size)||y>(lcddev.height-size)) return; bHz=0;//有汉字库 if(size==32) GUI_DrawFont32(x,y,fc,bc,str,mode); else if(size==24) GUI_DrawFont24(x,y,fc,bc,str,mode); else GUI_DrawFont16(x,y,fc,bc,str,mode); str+=2; x+=size;//下一个汉字偏移 } } } /***************************************************************************** * @name :void Gui_StrCenter(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *str,uint8_t size,uint8_t mode) * @date :2018-08-09 * @function :Centered display of English and Chinese strings * @parameters :x:the bebinning x coordinate of the Chinese and English strings y:the bebinning y coordinate of the Chinese and English strings fc:the color value of Chinese and English strings bc:the background color of Chinese and English strings str:the start address of the Chinese and English strings size:the size of Chinese and English strings mode:0-no overlying,1-overlying * @retvalue :None ******************************************************************************/ void Gui_StrCenter(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *str,uint8_t size,uint8_t mode) { uint16_t len=strlen((const char *)str); uint16_t x1=(lcddev.width-len*8)/2; Show_Str(x1,y,fc,bc,str,size,mode); } /***************************************************************************** * @name :void Gui_Drawbmp16(uint16_t x,uint16_t y,const unsigned char *p) * @date :2018-08-09 * @function :Display a 16-bit BMP image * @parameters :x:the bebinning x coordinate of the BMP image y:the bebinning y coordinate of the BMP image p:the start address of image array * @retvalue :None ******************************************************************************/ void Gui_Drawbmp16(uint16_t x,uint16_t y,const unsigned char *p) //显示40*40 QQ图片 { int i; unsigned char picH,picL; LCD_SetWindows(x,y,x+240-1,y+240-1);//窗口设置 for(i=0;i<240*240;i++) { picL=*(p+i*2); //数据低位在前 picH=*(p+i*2+1); Lcd_WriteData_16Bit(picH<<8|picL); } LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复显示窗口为全屏 } 3、编译下载验证 实际现象,如下视频 源码: 总结:实际测试刷新率不是特别高,受限于时钟频率

  • 2025-02-28
  • 回复了主题帖: 【NUCLEO-U083RE开发板测评】05 STM32U0低功耗定时器

    wangerxian 发表于 2025-2-28 09:16 那确实还是低功耗好。低功耗定时器有什么其他不足吗? 不足之处及有以下几点: 1、通道没有高级定时器多; 2、不能进行互补输出功能;  

  • 2025-02-27
  • 回复了主题帖: 【NUCLEO-U083RE开发板测评】05 STM32U0低功耗定时器

    wangerxian 发表于 2025-2-26 21:22 其实想知道低功耗定时器和普通定时器功耗能差多少0.0 低功耗定时器在PWM模式时,只有2.4uA,在运行模式普通定时器,至少有400uA,差距还是挺大的

  • 2025-02-26
  • 发表了主题帖: 【NUCLEO-U083RE开发板测评】05 STM32U0低功耗定时器

    本帖最后由 怀揣少年梦 于 2025-2-26 15:04 编辑 本次测评来测试一下低功耗定时器。 一、低功耗定时器简介 1、是什么 LPTIM称为低功耗定时器,LPTIM 是一个 16 位定时器,其时钟源具有多样性,因此LPTIM 能够在 STM32U0 微控制器的大多数低功耗模式下保持运行状态。 具备以下特点: 1)具备多选独立时钟源方案 内部时钟源:LSE/LSI/HSI16/APB时钟; 外部时钟源:可以使用LPTIM_IN1的时钟作为时钟源 2)高达8个外部触发器 具有可配置的有效边沿:上升沿、下降沿和双边沿 带有数字毛刺滤波器以避免虚假触发 3)2 种操作模式 连续模式和单次模式 4)多通道 最多4个通道 5)能够在STOP模式下唤醒 功能框图如图   2、适用什么环境 主要应用于低功耗场景,如低功耗周期性任务、PWM控制、传感器数据采集等。 二、应用 低功耗定时器产生PWM 1)配置时钟,选择HSI为LPTIM时钟源     2)打开和配置定时器   3)编写代码 int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_LPTIM1_Init(); /* USER CODE BEGIN 2 */ HAL_Delay(5000); if (HAL_LPTIM_PWM_Start(&hlptim1, LPTIM_CHANNEL_3) != HAL_OK) { Error_Handler(); } /* Suspend Tick */ HAL_SuspendTick(); /* Enter in Stop mode */ __HAL_RCC_PWR_CLK_ENABLE(); HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); HAL_ResumeTick(); HAL_LPTIM_PWM_Stop(&hlptim1, LPTIM_CHANNEL_3); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } 4)测试验证 波形图:   功耗 源码  

  • 2025-02-12
  • 发表了主题帖: 【NUCLEO-U083RE开发板测评】04 STM32U0功耗有几何

    本次测评主要测量一下STM32U083进入低功耗模式的功耗情况. 一、U083有哪几种功耗模式 根据U083的参考手册,总共有7中低功耗模式: 睡眠模式、低功耗运行模式、低功耗休眠模式、停止模式0、停止模式1、停止模式2、待机模式、关断模式; 简单介绍一下U083几种功耗模式。   1、睡眠模式 CPU CLK 被关断,所有外设正常运行 2、低功耗运行模式 前提条件:时钟低于2Mhz;主要将内部电源进入低功耗模式实现 3、低功耗睡眠模式 从低功耗运行模式下进入该模式 4、停止模式 停止模式主要是关闭所有时钟(MSI\PLL\HSI16\HSE),RTC可以保持运行,一些其他外设可以有条件的运行,低功耗调整器还在运行 5、待机模式 低功耗调整器可以选择不运行,所有时钟被关闭。 6、关断模式 低功耗调整器关闭,所有时钟被关闭。 各个模式之间相互切换的关系图   各模式对比如下   二、功耗测试 1、编写测试代码 /* USER CODE BEGIN Header */ /** ****************************************************************************** * [url=home.php?mod=space&uid=1307177]@File[/url] : main.c * [url=home.php?mod=space&uid=159083]@brief[/url] : Main program body ****************************************************************************** * [url=home.php?mod=space&uid=1020061]@attention[/url] * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define RUN_MODE 0 #define SLEEP_MODE 0 #define LP_RUN_MODE 1 #define LP_SLEEP_MODE 0 #define STOP_MODE_0 0 #define STOP_MODE_1 0 #define STOP_MODE_2 0 #define STANDY_MODE 0 #define SHUTDOWN_MODE 0 /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ static void SYSCLKConfig_WAKEUP(void); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ GPIO_InitTypeDef GPIO_InitStruct; /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); /* USER CODE BEGIN 2 */ /* Enable Power Clock */ __HAL_RCC_PWR_CLK_ENABLE(); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET); HAL_Delay(5000); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET); #if STOP_MODE_0 #elif STOP_MODE_1 __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); #elif STOP_MODE_2 #elif SLEEP_MODE_1 #elif STANDY_MODE_1 #elif SHUTDOWN_MODE_1 #elif LP_SLEEP_MODE_1 #elif LP_RUN_MODE_1 #endif /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ /* Enable GPIOs clock */ #if !RUN_MODE || !LP_RUN_MODE __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_ALL; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* Disable GPIOs clock */ __HAL_RCC_GPIOA_CLK_DISABLE(); /* Suspend Tick increment to prevent wakeup by Systick interrupt. */ /* Otherwise the Systick interrupt will wake up the device within 1ms */ /* (HAL time base). */ HAL_SuspendTick(); #endif #if STOP_MODE_0 HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI); #elif STOP_MODE_1 HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI); #elif STOP_MODE_2 HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); #elif SLEEP_MODE HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI); #elif STANDY_MODE HAL_PWR_EnterSTANDBYMode(); #elif SHUTDOWN_MODE HAL_PWR_EnterSHUTDOWNMode(); #elif LP_SLEEP_MODE HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); #elif LP_RUN_MODE /* Enter LP RUN Mode */ HAL_PWREx_EnableLowPowerRunMode(); #endif /* Re-configure the system clock to 48 MHz based on MSI, enable and select PLL as system clock source (PLL is disabled in STOP mode) */ #if LP_RUN_MODE /* Disable low power run mode and reset the clock to initialization configuration */ //HAL_PWREx_DisableLowPowerRunMode(); #endif #if RUN_MODE || LP_RUN_MODE #else SYSCLKConfig_WAKEUP(); __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET); HAL_Delay(5000); #endif } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE2); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /** * @brief Configures system clock after wake-up from STOP: enable MSI, PLL * and select PLL as system clock source. * @param None * @retval None */ static void SYSCLKConfig_WAKEUP(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitTypeDef RCC_OscInitStruct = {0}; uint32_t pFLatency = 0; /* Enable Power Control clock */ __HAL_RCC_PWR_CLK_ENABLE(); /* Get the Oscillators configuration according to the internal RCC registers */ HAL_RCC_GetOscConfig(&RCC_OscInitStruct); /* After wake-up from STOP reconfigure the system clock: Enable HSI and PLL */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /* Get the Clocks configuration according to the internal RCC registers */ HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency); /* Select MSI as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, pFLatency) != HAL_OK) { Error_Handler(); } } /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ 2、测试结果 运行模式 0.5 低功耗运行模式 0.4 休眠模式 0.3 低功耗休眠模式 0.3 停止模式0 0.3 停止模式1 0.3 停止模式 0.3 待机模式 0.0018 关断模式 0.0017 整体来看,功耗是非常低了,在运行模式功耗低至0.5mA;在停止模式300uA.这功耗最适合做低功耗产品了。 测试数据: 运行模式 低功耗运行模式 停止模式、睡眠模式 待机模式 关断模式  

  • 2025-02-10
  • 回复了主题帖: 【NUCLEO-U083RE开发板测评】03 低功耗串口测试

    秦天qintian0303 发表于 2025-2-9 08:42 低功耗窗口在进入低功耗模式的时候还能接收到数据吗? 可以的

  • 2025-02-08
  • 发表了主题帖: 【NUCLEO-U083RE开发板测评】03 低功耗串口测试

    本帖最后由 怀揣少年梦 于 2025-2-8 16:37 编辑 本次测评主要测试一下低功耗串口打印功能、功耗功能。 一、低功耗串口 1、介绍 能够在STOP MODE下,还能正常运行串口,此时的串口是限制了一些功耗的。并且还可以在STOP mode下进行数据传输   2、使用场景 主要在极低功耗要求的场景下使用 3、特点 带FIFO; STOP mode可以唤醒; 可以调试,并能够进行RS485接收     二、实操 1、配置时钟   2、使能LPUART1   3、编写串口打印test代码 #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int _io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__*/ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ PUTCHAR_PROTOTYPE { uint8_t c=ch; HAL_UART_Transmit(&hlpuart1, &c, 1, 100); return ch; } #ifdef __GNUC__ __attribute__((weak)) int _write(int file, char *buf, int len) { int idx = 0; for(idx = 0; idx < len; idx++) { _io_putchar(*buf++); } return len; } #else __attribute__((weak)) int _write(int file, char *buf, int len) { return 0; } #endif /* __GNUC__*/ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_LPUART1_UART_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ printf("LPUART TEST\r\n"); HAL_Delay(1000); HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5); } /* USER CODE END 3 */ } 实测打印   4、编写STOP MODE 低功耗串口唤醒测试代码 void EnterExitStopModeProcess(void) { /* Specify MSI as the clock source used after wake up from stop mode */ __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI); /* wait for two seconds before test start */ HAL_Delay(2000); /* make sure that no LPUART transfer is on-going */ while (__HAL_UART_GET_FLAG(&hlpuart1, USART_ISR_BUSY) == SET); /* make sure that LPUART is ready to receive * (test carried out again later in HAL_UARTEx_StopModeWakeUpSourceConfig) */ while (__HAL_UART_GET_FLAG(&hlpuart1, USART_ISR_REACK) == RESET); /* set the wake-up event: * specify wake-up on RXNE flag */ WakeUpSelection.WakeUpEvent = UART_WAKEUP_ON_READDATA_NONEMPTY; if (HAL_UARTEx_StopModeWakeUpSourceConfig(&hlpuart1, WakeUpSelection) != HAL_OK) { Error_Handler(); } /* Enable the UART Wake UP from STOP mode Interrupt */ __HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_WUF); HAL_SuspendTick(); printf("enter stop mode\r\n"); /* enable MCU wake-up by LPUART */ HAL_UARTEx_EnableStopMode(&hlpuart1); /* ### Enter in Stop mode ########################################### */ HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // 进入停止模式之后,程序运行入口在这个地方 /* at that point, MCU has been awoken*/ SystemClock_Config_fromSTOP(); HAL_ResumeTick(); /* Wake Up on 4-bit address detection successful */ /* wait for some delay */ HAL_Delay(100); printf("exit stop mode\r\n"); } 实测串口日志   5、实测功耗 1)进入停止模式后   唤醒之后的功耗   源码如下:

  • 发表了主题帖: 【NUCLEO-U083RE开发板测评】02 RTC测试

    本帖最后由 怀揣少年梦 于 2025-2-8 15:13 编辑 本篇测评开始测试STM32U083的RTC,主要使用RTC产生秒中断,持续观察一下RTC的时间精度 一、RTC介绍 1、特性 日历功能 拥有两个可编程闹钟 支持唤醒定时器   RTC还是和其他MCU一样,具备常用功能。 二、RTC如何配置 1、使能RTC   2、配置RTC时间,并屏蔽时分、日的闹钟   3、使能中断   4、编写代码 rtc.c //设置闹钟 void SetRtcAlarm(void) { /*The Alarm register can only be written when the corresponding Alarm is disabled (Use the HAL_RTC_DeactivateAlarm()).*/ RTC_TimeGet(); HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A);//必须失能ALARM,才能进行写寄存器 sAlarm.AlarmTime.Seconds = sysTim.sec + 1; if(sAlarm.AlarmTime.Seconds==60) { sAlarm.AlarmTime.Seconds=0; } HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN); } //中断回调函数 void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc) { g_secFlag = 1; SetRtcAlarm(); } //获取时间 void RTC_TimeGet( void ) { RTC_TimeTypeDef sTime; RTC_DateTypeDef sDate; HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN); sysTim.hour = sTime.Hours; sysTim.min = sTime.Minutes; sysTim.sec = sTime.Seconds; sysTim.month = sDate.Month; sysTim.day = sDate.Date; sysTim.year = sDate.Year ; } //设置时间 void RTC_TimeSet( void ) { RTC_TimeTypeDef sTime; RTC_DateTypeDef sDate; sTime.Hours = sysTim.hour; sTime.Minutes = sysTim.min; sTime.Seconds = sysTim.sec; sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; sTime.StoreOperation = RTC_STOREOPERATION_RESET; if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } sDate.WeekDay = RTC_WEEKDAY_SATURDAY; sDate.Month = sysTim.month ; sDate.Date = sysTim.day ; sDate.Year = sysTim.year ; if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } } main.c int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ SystemPower_Config(); /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_RTC_Init(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ if (g_secFlag) { g_secFlag = 0; HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5); RTC_TimeGet(); printf("%d-%d-%d %d:%d:%d\r\n",2000 + sysTim.year,sysTim.month,sysTim.day,sysTim.hour,sysTim.min,sysTim.sec); } } /* USER CODE END 3 */ } 三、下载验证 串口打印   1小时之后   从以上看,1小时RTC的精度相差了0.25s ,测试一天的时间精度相差在0.6s,精度还是相当不错的。 源码如下

  • 回复了主题帖: 官方NUCLEO-U083RC开发板识别不到下载口

    nmg 发表于 2025-2-8 14:04 我发现现在的数据线,坑挺多的,最让人想不到的是,手机官方带的线,竟然还不是数据线,只能充电,我过年 ... 那真是巨坑啊,官方带的线应该都是支持数据传输的

  • 回复了主题帖: 这个春节最火爆的AI大模型deepseek,你玩了吗?

    使用了一下,让其帮忙设计单片机最小系统,回答的还是比较准确的,就是不能绘制电路图

  • 2025-02-06
  • 回复了主题帖: 官方NUCLEO-U083RC开发板识别不到下载口

    最终换了一根线就好了。

  • 2025-01-28
  • 回复了主题帖: 官方NUCLEO-U083RC开发板识别不到下载口

    lugl4313820 发表于 2025-1-27 11:19 有几种情况,开发板上有时会有一个跳线,如果跳线没有接上,那MCU没有上电,他就识别不到。 还有就是有 ... 多谢大佬,检查了跳线,是没有问题的。数据线是新的,我换一根试试

  • 2025-01-25
  • 发表了主题帖: 官方NUCLEO-U083RC开发板识别不到下载口

    背景: 基于NUCLEO-U083RC开发板 ,使用type-c的供电; 现象: 插到电脑上,ST-LINK驱动能识别到。     在KEIL里面识别不到下载口   测量电压电压5V,MCU的VDD电压也为3.3V,求大佬指教一二。

  • 2025-01-24
  • 回复了主题帖: 【NUCLEO-U083RE开发板测评】01 STM32U0魅力何在

    秦天qintian0303 发表于 2025-1-24 10:33 低功耗是这个系列最主要的特点    是的,大佬。后续实际测试一下低功耗模式下的功耗

  • 发表了主题帖: 【NUCLEO-U083RE开发板测评】01 STM32U0魅力何在

    感谢EEWORLD给予这次测评的机会,也许久没有在论坛参加测评活动。也非常开心获得U083开发板的测评,曾在ST的公号里看到U0系列能够在太阳能板供电的情况进行数据传输以及正常工作,足见其功耗性能是很强的。那我们就先来看看U0系列有哪些吸引人的地方? 魅力之一:功耗 1、官方数据手册数据如下: 关断模式16nA; 待机模式:30nA;带RTC时,160nA; 停止模式2:695nA;带RTC时,有825nA; 由此可知,U083的功耗是真的低,竟然达到nA级别; 2、看看具体官方数据表 测试条件:所有外设失能,外部有源晶振; 1)运行模式和低功耗运行模式功耗如下 从上表可以看出 a、在2MHz运行模式功耗,不到250uA;且随着温度升高,功耗升高; b、在2Mhz低功耗运行模式,与运行模式相差70uA左右; 2)停止模式功耗如下 停止模式0 停止模式1 停止模式2 从上表可以看出,功耗情况为 stop mode 0 > stop mode 1 > stop mode 2;整体都在uA级别; 3)待机模式 从上表可以看出,待机模式的功耗处于nA级别 4)关断模式 从上表可知,关断模式的功耗比待机模式的还要低; 魅力之二:外设 1、拥有丰富的外设 1)模拟外设(独立供电) 带PGA的运放和两个低功耗比较器 2)20个通信接口 串口就有7个,I2C有4个; 3)10个定时器 有3个可在停止模式运行的低功耗定时器 4)高达20个电容感应通道 魅力之三:安全 1、U0支持读保护; 2、硬件保护; 3、支持安全启动 4、支持AES加解密       从整体来看,U0系列适合低功耗应用,很强,外设丰富,可以用来做很多小东西。唯一遗憾的是,没有CAN,之后在选型的时候差点就用上这个U0了,但是没有CAN。

  • 2025-01-19
  • 回复了主题帖: 【测评入围名单(最后1批)】年终回炉:FPGA、AI、高性能MCU、书籍等65个测品邀你来~

    个人信息无误,确认可以完成测评计划

  • 2025-01-17
  • 回复了主题帖: 【新年新挑战,任务打卡赢好礼!】第一批获奖名单公布

    已确认

  • 2025-01-16
  • 回复了主题帖: 求推荐代码检查工具

    吾妻思萌 发表于 2025-1-15 20:40 你是什么语言 怎么可能没有 Rust都有很好用的 C语言。之前用过CPPcheck,不是很好用

  • 2025-01-15
  • 回复了主题帖: 求推荐代码检查工具

    wangerxian 发表于 2025-1-15 13:22 肯定有的,我觉得VSCode是目前市场上非常好用的编辑器了。 没找到合适的插件

最近访客

< 1/6 >

统计信息

已有241人来访过

  • 芯积分:973
  • 好友:3
  • 主题:70
  • 回复:231

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言