(转载) min()的宏定义中的(void) (&_x == &_y)的含义

本文深入解析了C语言中min宏定义中的(void)(&_x==&_y)表达式的含义,揭示了其在进行类型检查时的巧妙运用。通过增加局部变量_x和_y,并利用指针比较引发编译器警告来确保参数类型一致,避免了副作用的发生。

Original Address:http://www.crifan.com/2010/08/13/order_min__macro_definition_void_amp__x__amp__y_the_meaning_of/

【整理】min()的宏定义中的(void) (&_x == &_y)的含义

近日无意间发现,关于常见的min的宏定义,在Linux中是这样的:

/*
* min()/max()/clamp() macros that also do
* strict type-checking.. See the
* "unnecessary" pointer comparison.
*/
#define min(x, y) ({     
typeof(x) _x = (x);    
typeof(y) _y = (y);    
(void) (&_x == &_y);   
_x < _y ? _x : _y; })

关于其中的:

(void) (&_x == &_y);

很是疑惑,表面看起来,这句话,好像不起作用,算是一句废话,所以去找了一下别人的解释,才大概搞懂是啥意思。

首先,我们此处想要实现的目的是,在计算两个数的最小值之前,希望去判断一下两个值的类型是否一致,而由于C语言本身不支持我们去做类似于这样的操作typeof(_x)==typeof(_y),所以在此,通过故意判断他们2个的地址指针是否相等,而显然&_x,即x的地址,是不可能等于&_y的,但是这句话(void) (&_x == &_y);使得,如果_x和_y的类型不一样,其指针类型也会不一样,2个不一样的指针类型进行比较操作,则会引起编译器产生一个编译警告,提示你这两个值的类型不同。

比如,如果你编译下面这段代码:

int x = 2;
char y = 3;
int m;
m = min(x,y);

编译的时候,经过预处理后,就会有这样的判断操作:

int * == char *;

因此编译器就会提示你:

warning: comparison of distinct pointer types lacks a cast

所以,这个宏的巧妙之处就在于此。

所以,总结起来就是:

(void) (&_x == &_y); 用于判断输入的两个值的类型是否是一致的。如果不一致,那么编译器就会做出如下警告:warning: comparison of distinct pointer types lacks a cast

【提示】

1。其实关于min的宏,更好的做法是再加个const,即:

  1. #define min(x, y) ({
  2. const typeof(x) _x = (x);
  3. const typeof(y) _y = (y);
  4. (void) (&_x == &_y);
  5. _x < _y ? _x : _y; })

2。(void) (&_x == &_y); 中的void,表示将表达式(&_x == &_y); 所得到的结果(此处肯定是逻辑上的假,值为0)忽略掉。如果不加void,则会提示你这行代码是无意义的,没人用到。

3。关于min的宏定义,为何这么复杂,而不是用简单的#define min(x,y) ((x) < (y) ? x : y)

因为,如果如此定义,那么对于一些特殊的值传入此宏之后,就会产生一些副作用,产生的结果,就不是我们想要的了,比如:

  min(++a,++b) ==> ((++a)<(++b))?(++a) : (++b) 
就使得,a++和b++分别执行了2次,而且min的结果,也不对了。而用上面那个复杂的定义,多加了局部变量_x和_y,就可以避免此类问题了。

【引用】

1。(void) (&_x == &_y);

http://hi.baidu.com/huahua9901/blog/item/9640223f2a37773470cf6cc4.html

2。如下的宏定义中(void) (&_x == &_y);是怎么做到判断类型的?

http://linux.chinaunix.net/bbs/viewthread.php?tid=1161263

3。Linux内核中的Min和Max函数

http://www.armfans.net/thread-1527-1-1.html

防君子不防也无法防小人的声明: 
如未注明转载则均为crifan原创,对于原创文章,转载请注明出处: 在路上 - on the way 
本文链接: 【整理】min()的宏定义中的(void) (&_x == &_y)的含义
MM32F0163项目,新建一个查表法的表单,以下是我相关程序#define WADC_0MM 2589 #define WADC_1MM 2542 #define WADC_2MM 2495 #define WADC_16MM 1851 #define WADC_17MM 1795 #define WADC_18MM 1731 #define MIN_ADC WADC_18MM #define MAX_ADC WADC_0MM const uint16_t W_seg_points[SEGMENTS+1][2]= { {WADC_0MM,50}, //x1,y1(5%占空比) 0mm {WADC_1MM,95}, //x2,y2(9.5%占空比) 1mm {WADC_2MM,140}, //x3,y3(14.0%占空比) 2mm {WADC_16MM,770}, //x4,y4(77.0%占空比) 16mm {WADC_17MM,815}, //x5,y5(81.5%占空比) 17mm {WADC_18MM,860}, //x6,y6(86.0%占空比) 18mm }; uint16_t W_pwm_lookup_table[MAX_ADC-MIN_ADC+1]; void InitLookupTable_W() { for(uint8_t seg=0; seg&lt;SEGMENTS; seg++) { uint16_t x_start = W_seg_points[seg][0]; uint16_t x_end = W_seg_points[seg+1][0]; uint16_t y_start = W_seg_points[seg][1]; uint16_t y_end = W_seg_points[seg+1][1]; int32_t delta_x = (int32_t)x_end - x_start; int32_t step = (delta_x &gt; 0) ? 1 : -1; uint32_t iterations = abs(delta_x); for(uint32_t i=0; i&lt;=iterations; i++) { uint32_t x = x_start + i*step; // 带符号的精确计算 int32_t numerator = (int32_t)(x - x_start) * (y_end - y_start); int32_t denominator = delta_x; uint16_t y = y_start + (uint16_t)(numerator / denominator); // 计算数组偏移量 uint32_t idx = x - MIN_ADC; if(idx &lt;= (MAX_ADC - MIN_ADC)) { W_pwm_lookup_table[idx] = y; } printf(&quot;x=%d, y_calc=%d, y_expected=%.1f\r\n&quot;, x, y, y_start + (x - x_start)*(float)(y_end - y_start)/(x_end - x_start)); } } }这是相关函数,然后是主函数初始化,然后调用相关语句如下 InitLookupTable_W();// 初始化查找表 WcompareValue=W_pwm_lookup_table[ch7_median];程序的问题是:当我变量ch7_median值为WADC_XMM跟WADC_(X+1)MM中间的一个值时,W_pwm_lookup_table[]输出的不是这中间的一个值,而是定义的端点值,通过打印串口数据,数据如下: x=2589、y_calc=50、y_expected=50.0 x=2588, y_calc=50, y_expected=-4112202752.0 x=2587, y_calc=51, y_expected=-4112202752.0 x=2586, y_calc=52, y_expected=-4112202752.0 x=2585, y_calc=53, y_expected=-4112202752.0 x=2584, y_calc=54, y_expected=-4112202752.0 x=2583, y_calc=55, y_expected=-4112202752.0 x=2582, y_calc=56, y_expected=-4112202752.0 x=2581, y_calc=57, y_expected=-4112202752.0 &hellip; x=2542, y_calc=95, y_expected=-4112202752.0 x=2542, y_calc=95, y_expected=95.0 x=2541, y_calc=95, y_expected=-4112202752.0 x=2540, y_calc=96, y_expected=-4112202752.0 &hellip; x=2495, y_calc=140, y_expected=-4112202752.0 x=2495, y_calc=140, y_expected=140.0 x=2494, y_calc=140, y_expected=-4201598208.0 &hellip; x=1851, y_calc=770, y_expected=-4201597440.0 x=1851, y_calc=770, y_expected=770.0 x=1850, y_calc=770, y_expected=-3451312128.0 &hellip; x=1795, y_calc=815, y_expected=-3451312128.0 x=1795, y_calc=815, y_expected=815.0 x=1794, y_calc=815, y_expected=-3019898112.0 x=1793, y_calc=816, y_expected=-3019898112.0 &hellip;
03-31
#include &ldquo;stm32f10x.h&rdquo; #include &ldquo;math.h&rdquo; #include &ldquo;delay.h&rdquo; // 舵机参数定义 #define PWM_PERIOD 20000 // 20ms周期 #define MIN_PULSE 500 // 0.5ms脉冲宽度 #define MAX_PULSE 2500 // 2.5ms脉冲宽度 #define ANGLE_RANGE 270.0f // 舵机角度范围 // 云台参数 #define CENTER_X 135.0f // 水平中心角度 #define CENTER_Y 135.0f // 垂直中心角度 #define RECT_WIDTH 10.0f // 矩形宽度 #define RECT_HEIGHT 10.0f // 矩形高度 #define STEPS_PER_SIDE 100 // 每条边的步数 // 函数声明 void PWM_Init(void); void Set_Servo_Angle(uint8_t servo_id, float angle); float LinearInterpolate(float start, float end, float ratio); void MoveToPoint(float x, float y, uint16_t steps); void DrawRectangle(void); // 确保起点终点重合的完整矩形 void Go_To_Center(uint16_t steps); // 当前位置存储(全局变量) float current_x = CENTER_X; float current_y = CENTER_Y; /** 函 数:PWM初始化 / void PWM_Init(void) { / 开启时钟 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); /* GPIO初始化 */ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &amp;GPIO_InitStructure); /* 配置时钟源 */ TIM_InternalClockConfig(TIM2); /* 时基单元初始化 */ TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = PWM_PERIOD - 1; TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &amp;TIM_TimeBaseInitStructure); /* 输出比较初始化 */ TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCStructInit(&amp;TIM_OCInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; TIM_OC2Init(TIM2, &amp;TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_OC3Init(TIM2, &amp;TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_Cmd(TIM2, ENABLE); } /** 函 数:设置舵机角度 */ void Set_Servo_Angle(uint8_t servo_id, float angle) { if (angle &lt; 0) angle = 0; if (angle &gt; ANGLE_RANGE) angle = ANGLE_RANGE; uint16_t pulse = MIN_PULSE + (uint16_t)((MAX_PULSE - MIN_PULSE) * angle / ANGLE_RANGE); switch(servo_id) { case 0: TIM_SetCompare2(TIM2, pulse); break; case 1: TIM_SetCompare3(TIM2, pulse); break; } } /** 函 数:线性插值 */ float LinearInterpolate(float start, float end, float ratio) { return start + ratio * (end - start); } /** 函 数:移动到指定点 */ void MoveToPoint(float x, float y, uint16_t steps) { for (uint16_t i = 0; i &lt;= steps; i++) { float ratio = (float)i / steps; float interp_x = LinearInterpolate(current_x, x, ratio); float interp_y = LinearInterpolate(current_y, y, ratio); Set_Servo_Angle(0, interp_x); Set_Servo_Angle(1, interp_y); delay_ms(2); } current_x = x; current_y = y; } /** 函 数:云台归中 */ void Go_To_Center(uint16_t steps) { MoveToPoint(CENTER_X, CENTER_Y, steps); } /** 函 数:绘制完整矩形(起点和终点重合) */ void DrawRectangle(void) { // 计算矩形的四个顶点 float top_left_x = CENTER_X - RECT_WIDTH/2; float top_left_y = CENTER_Y - RECT_HEIGHT/2; float top_right_x = CENTER_X + RECT_WIDTH/2; float top_right_y = CENTER_Y - RECT_HEIGHT/2; float bottom_right_x = CENTER_X + RECT_WIDTH/2; float bottom_right_y = CENTER_Y + RECT_HEIGHT/2; float bottom_left_x = CENTER_X - RECT_WIDTH/2; float bottom_left_y = CENTER_Y + RECT_HEIGHT/2; // 绘制完整矩形路径(4条边) MoveToPoint(top_left_x, top_left_y, STEPS_PER_SIDE); // 起点:左上角 MoveToPoint(top_right_x, top_right_y, STEPS_PER_SIDE); // 右上角 MoveToPoint(bottom_right_x, bottom_right_y, STEPS_PER_SIDE); // 右下角 MoveToPoint(bottom_left_x, bottom_left_y, STEPS_PER_SIDE); // 左下角 MoveToPoint(top_left_x, top_left_y, STEPS_PER_SIDE); // 终点:返回起点(左上角) } 我在云台上加了一个激光灯,请在此代码的基础上,补充代码,添加一个可以控制激光灯亮灭的代码
07-30
/* * BOWL.c * * Created on: 2025年6月26日 * Author: logan */ #include &quot;debug.h&quot; #include &quot;BOWL.h&quot; #include &lt;stdlib.h&gt; // 初始化TIM1 PWM输出 float current_pan_angle = 0; // 水平角度 float current_tilt_angle = 0; // 垂直角度 void TIM3_PWM_Init(void) { // 使能GPIO和TIM3时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 配置PB0, PB1, PB2为复用推挽输出(假设这三个引脚对应TIM3_CH3, TIM3_CH4, TIM3_ETR) GPIO_InitTypeDef GPIO_InitStructure={0}; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &amp;GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &amp;GPIO_InitStructure); // 定时器参数初始化 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Prescaler = 89; // 预分频值,根据系统时钟计算 TIM_TimeBaseStructure.TIM_Period = 19999; // 自动重载值,决定PWM频率 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3, &amp;TIM_TimeBaseStructure); // PWM模式配置 TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 1500; // 初始脉冲宽度,即占空比 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 设置不同通道 TIM_OC3Init(TIM3, &amp;TIM_OCInitStructure); // CH3 TIM_OC4Init(TIM3, &amp;TIM_OCInitStructure); // CH4 TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); // 启动定时器 TIM_Cmd(TIM3, ENABLE); } void SetServoAngle(uint8_t channel, float angle, uint16_t duration_ms) { if(channel &lt; 3 || channel &gt; 4) return; if(channel == 3) { current_pan_angle = angle; } else { current_tilt_angle = angle; } uint16_t target_pulse = SERVO_MIN_PULSE + (uint16_t)((angle + 90) * SERVO_RANGE / 180.0f); if(target_pulse &lt; SERVO_MIN_PULSE) target_pulse = SERVO_MIN_PULSE; if(target_pulse &gt; SERVO_MAX_PULSE) target_pulse = SERVO_MAX_PULSE; switch(channel) { case 3: TIM_SetCompare3(TIM3, target_pulse); break; // PB0 - 水平转动 case 4: TIM_SetCompare4(TIM3, target_pulse); break; // PB1 - 垂直转动 } if(duration_ms &gt; 0) { Delay_Ms(duration_ms); } } // 处理接收到的火焰坐标 void ProcessFlamePosition(int16_t flame_x, int16_t flame_y) { // 由于摄像头反装,对坐标取反 flame_x = -flame_x; flame_y = -flame_y; int16_t dx = flame_x - IMG_CENTER_X; int16_t dy = flame_y - IMG_CENTER_Y; if(abs(dx) &lt; DEAD_ZONE) dx = 0; if(abs(dy) &lt; DEAD_ZONE) dy = 0; float new_pan_angle = current_pan_angle - dx * KP; float new_tilt_angle = current_tilt_angle + dy * KP; new_pan_angle = (new_pan_angle &gt; MAX_ANGLE) ? MAX_ANGLE : ((new_pan_angle &lt; -MAX_ANGLE) ? -MAX_ANGLE : new_pan_angle); new_tilt_angle = (new_tilt_angle &gt; MAX_ANGLE) ? MAX_ANGLE : ((new_tilt_angle &lt; -MAX_ANGLE) ? -MAX_ANGLE : new_tilt_angle); SetServoAngle(3, new_pan_angle, 10); // 通道3 - 水平转动 SetServoAngle(4, new_tilt_angle, 10); // 通道4 - 垂直转动 // 调试输出 printf(&quot;Adjusted Flame@(%d,%d) -&gt; Pan:%.1f Tilt:%.1f\r\n&quot;, flame_x, flame_y, new_pan_angle, new_tilt_angle); } // UART数据接收处理 void UART_ReceiveHandler(void) { static uint8_t rx_buffer[10]; static uint8_t rx_index = 0; while(USART_GetFlagStatus(USART3, USART_FLAG_RXNE)) { uint8_t byte = USART_ReceiveData(USART3); // 检查帧头 if(rx_index == 0 &amp;&amp; byte != 0xFE) continue; if(rx_index == 1 &amp;&amp; byte != 0xFF) { rx_index = 0; continue; } rx_buffer[rx_index++] = byte; // 接收到完整数据包(2头+4x+4y) if(rx_index &gt;= 10) { // 解析坐标数据 (小端格式) int16_t flame_x = (int16_t)(rx_buffer[2] | (rx_buffer[3] &lt;&lt; 8)); int16_t flame_y = (int16_t)(rx_buffer[6] | (rx_buffer[7] &lt;&lt; 8)); // 处理火焰位置 ProcessFlamePosition(flame_x, flame_y); rx_index = 0; } } } void USART3_INIT(void){ // 初始化USART3 (与OpenMV通信) GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; // 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); // 配置USART3引脚 (PB10-TX, PB11-RX) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &amp;GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB, &amp;GPIO_InitStructure); // 配置USART3 USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART3, &amp;USART_InitStructure); USART_Cmd(USART3, ENABLE); } 位置取反后机械臂不运作了,因为openmv摄像头需要倒过来装,所以原本的定位需要取反后才能实现跟踪,修改代码
07-10
#include &lt;reg52.h&gt; #include &lt;intrins.h&gt; // 1602 LCD引脚定义 sbit LCD_RS = P2^0; sbit LCD_RW = P2^1; sbit LCD_EN = P2^2; #define LCD_DATA P0 // DS18B20温度传感器引脚 sbit DQ = P3^7; // 蜂鸣器引脚 sbit BEEP = P2^3; // 按键引脚定义 sbit KEY_SET = P1^0; // 设置键 sbit KEY_UP = P1^1; // 加键 sbit KEY_DOWN = P1^2; // 减键 sbit KEY_OK = P1^3; // 确认键 // 全局变量 unsigned char hour = 12, minute = 0, second = 0; unsigned char set_flag = 0; // 设置标志 unsigned char set_position = 0; // 设置位置 unsigned char count_down_minutes = 0; // 倒计时分钟数 unsigned char count_down_seconds = 0; // 倒计时秒数 unsigned char count_down_active = 0; // 倒计时激活标志 bit alarm_enabled = 1; // 整点报警使能 // 温度变量 int temperature = 0; // 函数声明 void Delayms(unsigned int ms); void LCD_WriteCmd(unsigned char cmd); void LCD_WriteData(unsigned char dat); void LCD_Init(void); void LCD_ShowString(unsigned char x, unsigned char y, unsigned char *str); void DS18B20_Init(void); void DS18B20_WriteByte(unsigned char dat); unsigned char DS18B20_ReadByte(void); void DS18B20_GetTemp(void); void Timer0_Init(void); void Key_Scan(void); void Beep(unsigned int time); void Display_Time_Temp(void); void Display_CountDown(void); // 延时函数 void Delayms(unsigned int ms) { unsigned int i, j; for(i = ms; i &gt; 0; i--) for(j = 110; j &gt; 0; j--); } // LCD写命令 void LCD_WriteCmd(unsigned char cmd) { LCD_RS = 0; LCD_RW = 0; LCD_DATA = cmd; LCD_EN = 1; _nop_(); _nop_(); LCD_EN = 0; Delayms(2); } // LCD写数据 void LCD_WriteData(unsigned char dat) { LCD_RS = 1; LCD_RW = 0; LCD_DATA = dat; LCD_EN = 1; _nop_(); _nop_(); LCD_EN = 0; Delayms(2); } // LCD初始化 void LCD_Init(void) { LCD_WriteCmd(0x38); // 16*2显示,5*7点阵,8位数据 LCD_WriteCmd(0x0c); // 开显示,不显示光标 LCD_WriteCmd(0x06); // 写入新数据后光标右移 LCD_WriteCmd(0x01); // 清屏 } // 在指定位置显示字符串 void LCD_ShowString(unsigned char x, unsigned char y, unsigned char *str) { unsigned char i = 0; if(y == 0) LCD_WriteCmd(0x80 + x); else LCD_WriteCmd(0xc0 + x); while(str[i] != &#39;\0&#39;) { LCD_WriteData(str[i]); i++; } } // DS18B20初始化 void DS18B20_Init(void) { unsigned char x = 0; DQ = 1; _nop_(); DQ = 0; Delayms(8); // 延时480us以上 DQ = 1; Delayms(1); // 等待15-60us x = DQ; Delayms(20); } // DS18B20写一个字节 void DS18B20_WriteByte(unsigned char dat) { unsigned char i; for(i = 0; i &lt; 8; i++) { DQ = 0; _nop_(); DQ = dat &amp; 0x01; Delayms(1); DQ = 1; dat &gt;&gt;= 1; } } // DS18B20读一个字节 unsigned char DS18B20_ReadByte(void) { unsigned char i, dat = 0; for(i = 0; i &lt; 8; i++) { dat &gt;&gt;= 1; DQ = 0; _nop_(); DQ = 1; _nop_(); if(DQ) dat |= 0x80; Delayms(1); } return dat; } // 获取温度 void DS18B20_GetTemp(void) { unsigned char tempL, tempH; int temp; DS18B20_Init(); DS18B20_WriteByte(0xcc); // 跳过ROM DS18B20_WriteByte(0x44); // 开始转换 Delayms(100); DS18B20_Init(); DS18B20_WriteByte(0xcc); // 跳过ROM DS18B20_WriteByte(0xbe); // 读温度 tempL = DS18B20_ReadByte(); tempH = DS18B20_ReadByte(); temp = tempH; temp &lt;&lt;= 8; temp |= tempL; temperature = temp * 0.0625 * 10; // 转换为实际温度值并放大10倍 } // 定时器0初始化 void Timer0_Init(void) { TMOD = 0x01; // 定时器0工作方式1 TH0 = 0x3C; // 50ms定时 TL0 = 0xB0; ET0 = 1; // 开启定时器0中断 TR0 = 1; // 启动定时器0 EA = 1; // 开启总中断 } // 蜂鸣器函数 void Beep(unsigned int time) { unsigned int i; for(i = 0; i &lt; time; i++) { BEEP = ~BEEP; Delayms(1); } BEEP = 1; // 关闭蜂鸣器 } // 按键扫描函数 void Key_Scan(void) { static unsigned char key_time = 0; if(KEY_SET == 0) { Delayms(10); if(KEY_SET == 0) { key_time++; if(key_time &gt; 100) key_time = 100; if(key_time == 1) { set_flag = 1; set_position = 1; // 进入时间设置模式 LCD_WriteCmd(0x0f); // 显示光标并闪烁 } } } else if(KEY_UP == 0) { Delayms(10); if(KEY_UP == 0) { if(set_flag == 1) { // 时间设置模式 switch(set_position) { case 1: hour = (hour + 1) % 24; break; case 2: minute = (minute + 1) % 60; break; } } else if(set_flag == 2) { // 倒计时设置模式 count_down_minutes = (count_down_minutes + 1) % 100; } } } else if(KEY_DOWN == 0) { Delayms(10); if(KEY_DOWN == 0) { if(set_flag == 1) { // 时间设置模式 switch(set_position) { case 1: hour = (hour + 23) % 24; break; case 2: minute = (minute + 59) % 60; break; } } else if(set_flag == 2) { // 倒计时设置模式 count_down_minutes = (count_down_minutes + 99) % 100; } } } else if(KEY_OK == 0) { Delayms(10); if(KEY_OK == 0) { if(set_flag == 1) { // 时间设置模式 set_position++; if(set_position &gt; 2) { set_flag = 2; // 进入倒计时设置模式 set_position = 0; LCD_WriteCmd(0x0c); // 关闭光标显示 } } else if(set_flag == 2) { // 倒计时设置模式 set_flag = 0; // 退出设置模式 if(count_down_minutes &gt; 0) { count_down_active = 1; count_down_seconds = 0; } LCD_WriteCmd(0x0c); // 关闭光标显示 } } } else { key_time = 0; } } // 显示时间和温度 void Display_Time_Temp(void) { unsigned char str[16]; // 显示时间 sprintf(str, &quot;Time:%02d:%02d:%02d&quot;, hour, minute, second); LCD_ShowString(0, 0, str); // 显示温度 sprintf(str, &quot;Temp:%2d.%1dC&quot;, temperature/10, temperature%10); LCD_ShowString(0, 1, str); } // 显示倒计时 void Display_CountDown(void) { unsigned char str[16]; if(count_down_active) { sprintf(str, &quot;Count:%02d:%02d&quot;, count_down_minutes, count_down_seconds); LCD_ShowString(0, 1, str); } } // 主函数 void main(void) { LCD_Init(); Timer0_Init(); LCD_ShowString(0, 0, &quot;Smart Clock V1.0&quot;); LCD_ShowString(0, 1, &quot;Initializing...&quot;); Delayms(1000); while(1) { Key_Scan(); DS18B20_GetTemp(); if(set_flag == 0) { Display_Time_Temp(); if(count_down_active) { Display_CountDown(); } } else if(set_flag == 1) { // 时间设置显示 unsigned char str[16]; sprintf(str, &quot;Set Time:%02d:%02d&quot;, hour, minute); LCD_ShowString(0, 0, str); LCD_ShowString(0, 1, &quot;UP/DOWN:Change &quot;); } else if(set_flag == 2) { // 倒计时设置显示 unsigned char str[16]; sprintf(str, &quot;CountDown:%02d:00&quot;, count_down_minutes); LCD_ShowString(0, 0, str); LCD_ShowString(0, 1, &quot;UP/DOWN:Change &quot;); } Delayms(200); } } // 定时器0中断服务函数 void Timer0_ISR() interrupt 1 { static unsigned int t0_count = 0; static unsigned int temp_count = 0; TH0 = 0x3C; TL0 = 0xB0; t0_count++; if(t0_count &gt;= 20) { // 1秒 t0_count = 0; second++; if(second &gt;= 60) { second = 0; minute++; if(minute &gt;= 60) { minute = 0; hour++; if(hour &gt;= 24) { hour = 0; } // 整点报警 if(alarm_enabled &amp;&amp; minute == 0 &amp;&amp; second == 0) { Beep(1000); } } } // 倒计时处理 if(count_down_active) { if(count_down_seconds == 0) { if(count_down_minutes == 0) { count_down_active = 0; Beep(2000); // 倒计时结束报警 } else { count_down_minutes--; count_down_seconds = 59; } } else { count_down_seconds--; } } } temp_count++; if(temp_count &gt;= 200) { // 10秒更新一次温度 temp_count = 0; // 温度更新在主循环中处理 } }
11-08
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值